【问题标题】:Implementing double dispatch with two class hierarchies in C++在 C++ 中使用两个类层次结构实现双重分派
【发布时间】:2011-05-25 22:25:56
【问题描述】:

我想创建一个事件调度系统,它具有(浅)事件层次结构,可以通过 EventObserver 的(浅)层次结构观察。我认为双重调度将允许各种事件和 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 类(例如 EventA)的 beObservedBy 方法,并使用派生 EventObserver 类,但调用的是 observe( BaseEvent* ) 函数而不是observe( EventA* )

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

【问题讨论】:

  • 我决定在 BaseObserver 上使用一系列的 observe() 方法,并根据需要在特定的 Observers 上覆盖它们。我看看模板化 observe() 函数是否有帮助。

标签: c++ events double-dispatch


【解决方案1】:

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

派生类中的签名必须与基类中的签名匹配,否则它不会覆盖它,它只是重载它(所以你最终会得到两个函数——一个接受EventA *,一个接受@ 987654326@).

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

【讨论】:

  • 啊,我以为重载会选择最合适的版本,但仔细想想,这可能没有很好的定义。
【解决方案2】:

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

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

【讨论】:

  • 那么缺点是(比如说)我的 BaseObserver 类必须对每个可能的事件都有观察功能?这很痛苦,但我猜你会得到一种原生不支持双分派的语言。
  • @BrettW 正确。第一次分派找出您正在分派的事件的类型。该信息需要作为第二次分派的一部分传递给观察者,第二次分派找出事件被分派到的观察者的类型。
【解决方案3】:

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

请记住,在 C++ 中,函数签名由函数名称和参数列表组成,在这种情况下

virtual void observe( BaseEvent* evt )

不同于

virtual void observe( EventA* evt )

【讨论】:

    猜你喜欢
    • 2011-01-22
    • 1970-01-01
    • 2015-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-06
    • 1970-01-01
    相关资源
    最近更新 更多