用C++实现两个类层次结构的双重调度

Implementing double dispatch with two class hierarchies in C++

本文关键字:层次结构 调度 两个 实现 C++      更新时间:2023-10-16

我想创建一个具有(浅层)EventObserver层次结构的事件调度系统。我认为双重调度将允许各种各样的Events和EventObserver,而不必为每个组合都有一个函数。

我有这样的代码:

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++中的双调度/多方法和维基百科上关于双调度的文章)

现在,当我调试双重调度时,会调用派生的Event类(比如EventA)的beObservedBy方法,并使用派生的EventObserver类,但会调用observe( BaseEvent* )函数,而不是observe( EventA* )

我做错了吗?我试着用引用而不是指针,但没有得到爱。

问题在于您在ObserverX中定义了observe(EventA *evt)。这会导致函数过载。但当您调用observe时,参数是BaseEvent *,而不是EventA *。因此,改为调用基类方法。

派生类中的签名必须与基类中的签名匹配,否则它不会覆盖它,只是重载它(因此最终会得到两个函数——一个使用EventA *,另一个使用BaseEvent *)。

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

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

在您的情况下,如果您将virtual void observe( EventA* evt )添加到BaseObserver类中,那么EventA::beObservedBy将调用该版本的observe方法,而ObserverX将正确地覆盖它。

首先,Observer X中observe的签名与基类中的签名不同,并且它没有覆盖基类中的虚拟void observe(BaseEvent*evt)方法。相反,您定义了一个以EventA*为参数的新函数。

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

virtual void observe( BaseEvent* evt )

与不同

virtual void observe( EventA* evt )