I want to create an event dispatch system with a (shallow) hierarchy of Events that can be observed by a (shallow) hierarchy of EventObservers. I figured double-dispatch would allow a wide variety of both Events and EventObservers without having to have a function for every single combination.
I have code like this:
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 ); }
Then define a few test classes:
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; }
};
(This was all following the lead of Double dispatch/multimethods in C++ and the Wikipedia art开发者_运维技巧icle on double dispatch )
Now when I debug the double-dispatch, the beObservedBy
method of the derived Event class (EventA
, say) is called, and the derived EventObserver class is used, but the observe( BaseEvent* )
function is called rather than the observe( EventA* )
Am I doing it wrong? I tried with using references instead of pointers and got no love.
The problem is that you define observe(EventA *evt)
in ObserverX.
This causes the function to be overloaded.
But when you call observe
, the parameter is BaseEvent *
and not EventA *
. So the base class method is called instead.
The signature in the derived class must match the one in the base class, otherwise it doesn't override it, it simply overloads it (so you end up with two functions - one that takes EventA *
and one that takes BaseEvent *
).
Try defining observe(BaseEvent *evt)
in ObserverX.
Either your base observer class needs to know how to observe any event type, or your base event class needs to know how to be observed by any observer type. Otherwise your double dispatch simply loses the type information gained from your initial dispatch.
In your case, if you added virtual void observe( EventA* evt )
to your BaseObserver
class then EventA::beObservedBy
would call that version of the observe method and ObserverX
would correctly override it.
Firstly, The signature of observe in ObserverX is different from the one in Base class and it does not override the virtual void observe( BaseEvent* evt ) method in the base class. Instead you are defining a new function that takes EventA* as an argument.
Remember in C++, the function signature consists of the Function name and the argument list and in this case
virtual void observe( BaseEvent* evt )
is different from
virtual void observe( EventA* evt )
精彩评论