1

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 article 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.

Community
  • 1
  • 1
BrettW
  • 37
  • 6
  • I've decided to go with a panoply of observe() methods on BaseObserver and override them as needed on specific Observers. I'm seeing if templating the observe() function would help. – BrettW May 26 '11 at 11:58

3 Answers3

2

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.

Omri Barel
  • 9,182
  • 3
  • 29
  • 22
  • Ah, I thought that overloading would choose the most appropriate version, but upon reflection, that might not be well-defined. – BrettW May 26 '11 at 07:57
1

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.

Neil
  • 54,642
  • 8
  • 60
  • 72
  • So the downside would be that (say) my BaseObserver class would have to have the observe function for every possible event? That's a pain, but I guess what you get for a language that doesn't support double-dispatch natively. – BrettW May 26 '11 at 07:55
  • @BrettW Correct. The first dispatch finds out the type of the Event which you are dispatching. This information needs to be passed to the Observer as part of the second dispatch which finds out the type of the Observer to which the Event is being dispatched. – Neil May 26 '11 at 20:58
0

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 )
user258808
  • 734
  • 4
  • 5