1

这段代码将问题提炼为本质:

基础设施类:

struct EventReceiverBase {
    virtual ~EventReceiverBase() { }
};

template<typename T>
struct EventReceiver : public virtual EventReceiverBase {
    virtual void receiveEvent(T* pSender) = 0;
};

struct EventSender {
    EventReceiverBase* pReceiver;

    template<typename T>
    void sendEvent(T* pSender) {
        EventReceiver<T>* pCastedReceiver =
            dynamic_cast<EventReceiver<T>*>(pReceiver);
        // HERE IS THE PROBLEM
        // pCastedReceiver is null. T is BaseSender. The pointer
        // being casted is really of type EventReceiver<DerivedSender>*,
        // but it tries to cast to EventReceiver<BaseSender>*, and that
        // fails.
        pCastedReceiver->receiveEvent(pSender);
    }
};

用户类别:

struct BaseSender : public virtual EventSender {
    void f() {
        sendEvent(this);
    }
};
struct DerivedSender : public BaseSender { };

struct MyClass : public virtual EventReceiver<DerivedSender> {
    void receiveEvent(DerivedSender* pSender) { }
};

int main() {
    MyClass my;
    DerivedSender derivedSender;
    derivedSender.pReceiver = &my;
    derivedSender.f();
}

我可以改写这个问题(没有双关语)以避免这个问题吗?我希望使用户类尽可能简单,同时尽可能接近这种方式公开事件发送和接收功能。

例如,我可以通过让 MyClass 也从 EventReceiver<BaseSender> 派生来“修复”它,但我真的很想避免这种情况,因为这意味着每个接收事件的类都需要额外的工作。

编辑:可执行粘贴: http: //liveworkspace.org/code/4bm6OU $13

4

2 回答 2

1

您看到问题的原因与f函数在BaseSender: 中的位置有关,在下面的调用sendEvent中,this表示指向BaseSender. 本质上,下面的调用

void f() {
    sendEvent(this);
}

是写这个的简短方法:

void f() {
    sendEvent<BaseSender>(this);
}

移动fDerivedSender 解决这个问题

另一种选择是制作BaseSender::f模板:

template <typename T>
void f() {
    sendEvent<T>((T*)this);
}

并这样称呼它:

derivedSender.f<DerivedSender>();

这看起来不是特别好,但可能是在现实世界f很大的情况下代码复制粘贴的解决方法。

另一种解决方案是制作BaseSender一个模板,如下所示:

template<typename T>
struct BaseSender : public virtual EventSender {
    void f() {
        sendEvent((T*)this);
    }
};
struct DerivedSender : public BaseSender<DerivedSender> {
};

这也有效(链接到 ideone)。

于 2012-12-29T12:41:40.257 回答
0

这应该是个问题。pSender 将指向原始对象,除非您正在做一些非常奇怪的事情。

但是,您在 MyClass 中的 receiveEvent 应该接受一个BaseSender *对象,然后您必须将其强制转换为 DerivedSender (或者更好的是,仅使用基中定义的虚拟方法 - 这是您通常应该做的事情)

于 2012-12-29T12:30:05.457 回答