Это правильное использование полиморфизма? - PullRequest
10 голосов
/ 04 марта 2011

Рассмотрим этот синтаксически правильный (?) Псевдокод:

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 нет особого поведения ... они просто содержат некоторые данные ... Я злоупотребляю этим шаблоном?

Во-вторых, есть ли лучший способ сделать это?Я сильно упрощаю вещи здесь, но любые идеи будут оценены ...

РЕДАКТИРОВАТЬ Я обновил свой пример ... Короче говоря, классы обработки слушают события и должны приниматьдействие на основе события.Надеюсь, это поможет ...

Ответы [ 3 ]

1 голос
/ 04 марта 2011

Я предлагаю добавить 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();
    }
}
0 голосов
/ 06 марта 2011

Код ключа для ответа на ваш вопрос - две функции процесса и их функции.Неправильно ли передавать SpecialEvent или EventWrapper, производный от SpecialEvent, в функцию process(Event&)?Если это так, то это неуместное использование полиморфизма.

0 голосов
/ 05 марта 2011

Я немного поигрался с твоим кодом.Мне кажется, что вы пытаетесь сделать что-то очень похожее на boost :: any

Если нет, то мой главный совет - использовать настоящий абстрактный интерфейс как для Event, так и для SpecialEvent.У вас есть только частичный полиморфизм, потому что у SpecialEvent есть метод и, что еще более важно, метод IDENTITY, который не переопределяет Event :: getId.Это «очень плохо», и я верю, что гарантированно приведет вас к трудностям позже, когда вы начнете зависеть от концепции Id любым общим способом.

В вашем дизайне необходимо установить четкое различие между классом (тип) личность и объект (экземпляр) личность.Пока что вы, похоже, работаете только с идентификатором объекта (экземпляра), в противном случае ваш метод id () будет статическим. RTTI может использоваться для установления идентичности класса, но в зависимости от фактических производных типов является классическим анти-паттерном и обычно указывает на нарушенный полиморфизм.Я никогда не нуждался в RTTI, даже в целях регистрации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...