这段代码从本质上提炼了问题:
基础设施类:
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
编辑:可执行粘贴:http://liveworkspace.org/code/4bm6OU $13
最佳答案
您看到问题的原因与 BaseSender
中 f
函数的放置有关:在对 sendEvent
的调用中下面,this
表示指向 BaseSender
的指针。本质上,下面的调用
void f() {
sendEvent(this);
}
是一个简短的写法:
void f() {
sendEvent<BaseSender>(this);
}
将 f
移动到 DerivedSender
fixes this problem .
另一种方法是使 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> {
};
这也有效(link to ideone)。
关于c++ - 事件处理 : Sending events from base classes when the receiver expects derived classes,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14081637/