我正在学习c ++,并希望构建与C#事件类似的东西来处理嵌入式c ++项目中的中断。
到目前为止,我想出了一种解决方案,几乎可以满足我的需求。但是我需要多态性(?)的帮助。以下代码段是重现我的情况的一个最小示例:
#include <iostream>
struct Event
{ };
struct EventHandler
{
virtual void Esr (const Event& I) { }
};
struct EventSender
{
EventSender (EventHandler& Handler) : _Handler (Handler) { }
template <typename T>
void SendEvent (const T&) const
{
_Handler.Esr (T ());
}
EventHandler& _Handler;
};
struct SpecialEvent : public Event
{ };
struct MyHandler : public EventHandler
{
void Esr (const Event& I) override { std::cout << "Event" << std::endl; }
void Esr (const SpecialEvent& I) { std::cout << "SpecialEvent" << std::endl; }
};
int main()
{
MyHandler handler;
EventSender sender (handler);
/* Invoke directly */
handler.Esr (Event ());
handler.Esr (SpecialEvent ());
/* Invoke indirectly */
sender.SendEvent (Event ());
sender.SendEvent (SpecialEvent ()); // Expected cout msg: "SpecialEvent"
return 0;
}
预期的控制台输出:
Event
SpecialEvent
Event
SpecialEvent
实际控制台输出:
Event
SpecialEvent
Event
Event
我不知道的编译器/链接器是什么?
MyHandler中有两个方法。其中一个覆盖基类方法,另一个不覆盖。
一种解决方案是在基类中声明两个方法:
struct EventHandler
{
virtual void Esr (const Event& I) = 0;
virtual void Esr (const SpecialEvent& I) = 0;
};
这样,编译器可以使用参数的类型在EventHandler级别解析该方法。
如果要避免所有派生类都必须重载两个方法的要求,可以执行以下操作:
struct EventHandler
{
virtual void Esr (const Event& I) = 0;
virtual void Esr (const SpecialEvent& I)
{
// if not overridden, use the non-specialized event handler.
Esr(reinterpret_cast<const Event &>(I));
}
};
要回答您的问题:
我不知道的编译器/链接器是什么?
在C ++中,方法调用在编译/链接时解析为1)调用特定代码块(方法主体),或2)通过称为vtable的隐藏数据结构进行间接调用。实际的vtable是在运行时确定的,但是编译器必须决定要在表中使用哪个条目进行调用。(Google vtable提供了有关它们是什么以及如何实现的更多信息。)
它必须基于允许知道的解决方案。在这种情况下,基于调用该方法的指针或引用的类型。请注意,这不一定是实际对象的类型。
在您的情况下,当您通过调用handler
方法时,允许编译器知道在中声明的两个方法,MyHandler
以便可以选择所需的方法,但是当调用通过时sender
,它必须查找在中声明的方法EventSender
。中仅声明了一种方法EventSender
。幸运的是,该参数可以强制为,const Event &
以便编译器能够使用该方法。因此,它将vtable条目用于该方法。因此,它为MyHandler
[在运行时]找到了vtable并将vtable条目用于
Esr (const Event& I)
而这就是你如何在错误的方法结束。
顺便说一句:我的答案是要解释您所看到的内容,并为您解决当前问题的方法。杰里·科芬(Jerry Coffin)的答案为您提供了另一种方法,该方法从长远来看应该对您更好。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句