事件处理:当接收者期望派生类时,从基类发送事件
Event handling: Sending events from base classes when the receiver expects derived classes
这段代码将问题提炼到本质:
基础设施类:
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
您看到问题的原因与f
函数在BaseSender
中的位置有关:在下面的sendEvent
调用中,this
代表指向BaseSender
的指针。实际上,
void f() {
sendEvent(this);
}
是一个简短的写法:
void f() {
sendEvent<BaseSender>(this);
}
移动f
到DerivedSender
可以解决这个问题。
另一种选择是使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> {
};
这不应该是个问题。pSender将指向原始对象,除非你做了一些非常奇怪的事情。
然而,你的MyClass中的receiveEvent应该接受一个BaseSender *
对象,然后你必须将它强制转换为DerivedSender(或者更好的是,只使用在基类中定义的虚拟方法-这是你应该做的事情)
相关文章:
- std::具有相同基类的类的变体
- 是否可以初始化不可复制类型的成员变量(或基类)
- 在C++中,是否可以基于给定的标识符创建基类的新实例,反之亦然
- 基类中的函数名称解析
- C++初始化基类
- 如何通过派生类函数更改基类中的向量
- 如何定义一个纯抽象基类
- 如何使用基类指针引用派生类成员
- 继承:构造函数,初始化C++11中基类的类C数组成员
- 使用基类指针创建对象时,缺少派生类析构函数
- 如何引用基类的派生类?
- 如果基类包含双指针成员,则派生类的构造函数
- 在模板基类中为继承类中的可选重写生成虚拟方法
- 为什么此派生对象无法访问基类的后递减方法?
- 公开最直接的基类模板名称
- 当基类是依赖类型时,这是一个缺陷吗
- 如何使基类的运算符对基类的可变参数数可见(请参阅下面的代码)?
- 模板基类中的静态变量
- 具有从 c++ 中的非模板基类派生的模板类的事件系统
- 事件处理:当接收者期望派生类时,从基类发送事件