Реализация двойной диспетчеризации с двумя иерархиями классов в C ++ - PullRequest
1 голос
/ 26 мая 2011

Я хочу создать систему диспетчеризации событий с (мелкой) иерархией событий, которую может наблюдать (неглубокая) иерархия EventObservers.Я полагал, что двойная диспетчеризация позволила бы широкий спектр событий и EventObservers без необходимости иметь функцию для каждой отдельной комбинации.

У меня есть такой код:

class BaseObserver;

class BaseEvent {
public:

    virtual std::string getName() { return "BaseEvent"; }

    void beObservedBy( BaseObserver* obv );

};

class BaseObserver {
public:

    virtual void observe( BaseEvent* evt ) {

        std::cout << "BaseObserver observing: " << evt->getName() << "." << std::endl;

    }

};

void BaseEvent::beObservedBy( BaseObserver* obv ) { obv->observe( this ); }

Затем определитенесколько тестовых классов:

class EventA : public BaseEvent {
public:

    void beObservedBy( BaseObserver* obv ) { obv->observe( this ); }

    virtual std::string getName() { return "I am an EventA"; }

};

class EventB : public BaseEvent {
public:

    void beObservedBy( BaseObserver* obv ) { obv->observe( this ); }

    virtual std::string getName() { return "I am an EventB"; }

};

class ObserverX : public BaseObserver {

    virtual void observe( EventA* evt  ) {  std::cout << "ObserverX spotted an EventA" << std::endl; }

};

(Это все следовало примеру Двойная рассылка / мультиметоды в C ++ и статье Википедия о двойной рассылке )

Теперь, когда я отлаживаю двойную диспетчеризацию, вызывается метод beObservedBy производного класса Event (скажем, EventA), и используется производный класс EventObserver, но вызывается функция observe( BaseEvent* ), а неobserve( EventA* )

Я делаю это неправильно?Я пытался использовать ссылки вместо указателей и не получил любви.

Ответы [ 3 ]

2 голосов
/ 26 мая 2011

Проблема в том, что вы определяете observe(EventA *evt) в ObserverX.Это вызывает перегрузку функции.Но когда вы вызываете observe, параметр равен BaseEvent *, а не EventA *.Таким образом, вместо этого вызывается метод базового класса.

Сигнатура в производном классе должна совпадать с сигнатурой в базовом классе, в противном случае она не переопределяет ее, а просто перегружает (так что в итоге получается две функции- тот, который принимает EventA *, а другой - BaseEvent *).

Попробуйте определить observe(BaseEvent *evt) в ObserverX.

1 голос
/ 26 мая 2011

Либо ваш базовый класс наблюдателей должен знать, как наблюдать любой тип события, либо ваш базовый класс событий должен знать, как наблюдать любой тип наблюдателя.В противном случае ваша двойная отправка просто потеряет информацию о типе, полученную из вашей первоначальной отправки.

В вашем случае, если вы добавите virtual void observe( EventA* evt ) в свой класс BaseObserver, тогда EventA::beObservedBy вызовет эту версию метода наблюдения иObserverX правильно переопределит его.

0 голосов
/ 26 мая 2011

Во-первых, сигнатура наблюдения в ObserverX отличается от сигнатуры в базовом классе, и она не переопределяет метод виртуального пустого наблюдения (BaseEvent * evt) в базовом классе.Вместо этого вы определяете новую функцию, которая принимает EventA * в качестве аргумента.

Помните, что в C ++ сигнатура функции состоит из имени функции и списка аргументов, и в этом случае

virtual void observe( BaseEvent* evt )

отличается от

virtual void observe( EventA* evt )
...