在C ++中实现具有两个类层次结构的双分派

时间:2011-05-25 22:25:57

标签: c++ events double-dispatch

我想创建一个事件调度系统,其事件(浅层)可以通过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; }

};

(这完全是Double dispatch/multimethods in C++Wikipedia article on double dispatch

的引导

现在,当我调试双重调度时,调用派生的Event类(beObservedBy的{​​{1}}方法,然后使用派生的EventObserver类,但是{{1}调用函数而不是EventA

我做错了吗?我尝试使用引用而不是指针而没有爱。

3 个答案:

答案 0 :(得分:2)

问题是您在ObserverX中定义observe(EventA *evt)。 这会导致函数重载。 但是当您致电observe时,参数为BaseEvent *而非EventA *。所以改为调用基类方法。

派生类中的签名必须与基类中的签名匹配,否则它不会覆盖它,它只是重载它(所以你最终得到两个函数 - 一个取EventA *而另一个取{需要BaseEvent *)。

尝试在ObserverX中定义observe(BaseEvent *evt)

答案 1 :(得分:1)

您的基本观察者类需要知道如何观察任何事件类型,或者您的基本事件类需要知道任何观察者类型如何观察。否则,您的双重发送只会丢失从初始发送中获得的类型信息。

在您的情况下,如果您将virtual void observe( EventA* evt )添加到BaseObserver课程,则EventA::beObservedBy会调用该版本的观察方法,而ObserverX会正确覆盖它。

答案 2 :(得分:0)

首先,ObserverX中的observe签名与Base类中的签名不同,它不会覆盖基类中的虚拟void observe(BaseEvent * evt)方法。相反,您正在定义一个以EventA *作为参数的新函数。

请记住,在C ++中,函数签名由函数名和参数列表组成,在本例中为

virtual void observe( BaseEvent* evt )

不同
virtual void observe( EventA* evt )