Является ли это подходящим применением полиморфизма?
Рассмотрим этот синтаксически правильный (?) псевдокод:
class Event {
public:
virtual int getID() const = 0;
virtual int getSize() = 0;
virtual void* getData() = 0;
virtual void setData() = 0;
//(I cannot define data at this level 'cos I don't know what it is yet)
}
class SpecialEvent : class Event {
public:
virtual int getPGNID() const = 0;
int getSourceAddress() {return source_address;}
int setSourceAddress(int source_address) {this->source_address = source_address;}
protected:
int source_address;
}
template <typename T, typename E>
class EventWrapper : public E {
T data;
public:
static int EVENT_ID;
//implements everything in Event...EVENT_ID is assigned at runtime by some registry
}
class AnEvent : public EventWrapper<int, Event> {
//public methods specific to AnEvent...
}
class AnotherEvent : public EventWrapper<long, SpecialEvent> {
int getPGNID() const {static int ID = 10; return ID;}
}
class TheProcessingClass {
AnEvent event1;
AnotherEvent event2;
void process(Event& e);
void process(SpecialEvent& e);
void doSomething() {
process(event1); //should invoke process(Event&)
process(event2); //should invoke process(SpecialEvent&)
}
}
По существу, у меня есть класс-оболочка, который обертывает данные типа T и наследует от некоторого типа E
(в данном случае Event
или SpecialEvent
)...
Сначала я собирался создать два класса-оболочки EventWrapper
и SpecialEventWrapper
до тех пор, пока не выясню, что оба класса будут иметь в нем один и тот же код (если он распространяется от некоторого типа Event
)
Во-первых, это похоже на политический дизайн. Тем не менее, Events
не имеют какого-либо особого поведения... они просто содержат некоторые данные... Я злоупотребляю этим шаблоном?
Во-вторых, есть ли лучший способ сделать это? Я значительно упрощаю ситуацию здесь, но любые идеи будут оценены...
ИЗМЕНИТЬ
Я обновил свой пример... Короче говоря, классы обработки прослушивают события и должны принимать меры на основе события. Надеюсь, это поможет...
Ответы
Ответ 1
Я предлагаю добавить process() в качестве функции-члена события класса.
class Event {
int getID() const;
void process();
//class stuff
}
class SpecialEvent : class Event {
int getSpecialID() const;
void process(); //special version of process()
//class stuff
}
class TheProcessingClass {
Event event1;
SpecialEvent event2;
void doSomething() {
event1.process();
event2.process();
}
}
Ответ 2
Я играл с вашим кодом на некоторое время.
Мне кажется, что вы пытаетесь сделать что-то очень похожее на boost:: any
Если не мой основной совет - использовать истинный абстрактный интерфейс для Event и SpecialEvent. У вас есть только частичный полиморфизм из-за того, что у SpecialEvent есть метод и, что еще важнее, метод IDENTITY, который не переопределяет Event:: getId. Это "очень плохо", и я уверен, что это может привести к трудностям позже, когда вы будете зависеть от концепции Id каким-либо общим способом.
В вашем дизайне вам необходимо установить четкое различие между идентификатором класса (типа) и идентификатором объекта (экземпляра). Пока вы, похоже, работаете только с идентификатором объекта (экземпляра), иначе ваш метод (ы)() будет статичным.
RTTI может использоваться для определения идентичности класса, но в зависимости от фактических производных типов является классическим анти-шаблоном и обычно указывает на неработающий полиморфизм. Я никогда не нуждался в RTTI, даже для протоколирования.
Ответ 3
key code, чтобы ответить на ваш вопрос, являются две функции процесса и то, что они делают. Неправильно ли передавать SpecialEvent или EventWrapper, полученный из SpecialEvent, в функцию process(Event&)
? Если это так, то это не является подходящим полиморфизмом.