C++;我错过了什么? 我正在学习C++,想构建类似于C++事件的东西来处理嵌入式C++项目中的中断。
到目前为止,我提出了一个解决方案,几乎满足了我的需求。但是我需要一些多态性方面的帮助(?)。下面的代码片段是再现我的情况的一个最小示例:C++;我错过了什么? 我正在学习C++,想构建类似于C++事件的东西来处理嵌入式C++项目中的中断。,c++,templates,polymorphism,C++,Templates,Polymorphism,到目前为止,我提出了一个解决方案,几乎满足了我的需求。但是我需要一些多态性方面的帮助(?)。下面的代码片段是再现我的情况的一个最小示例: #include <iostream> struct Event { }; struct EventHandler { virtual void Esr (const Event& I) { } }; struct EventSender { EventSender (EventHandl
#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));
}
};
#include <iostream>
struct Event {
virtual void operator()() const { std::cout << "Event\n"; }
};
struct EventHandler {
void Esr(const Event& I) const { I(); }
};
struct EventSender {
template <typename T>
void SendEvent (const T& t) const {
handler.Esr(t);
}
EventHandler handler;
};
struct SpecialEvent : public Event {
virtual void operator()() const override { std::cout << "Special Event\n"; }
};
int main() {
EventHandler handler;
EventSender sender;
/* Invoke directly */
handler.Esr (Event ());
handler.Esr (SpecialEvent ());
/* Invoke indirectly */
sender.SendEvent (Event ());
sender.SendEvent (SpecialEvent ()); // Expected cout msg: "SpecialEvent"
}
这就是为什么你最终选择了错误的方法
顺便说一句:我的回答是为了解释你看到了什么,并给你一个解决眼前问题的方法。Jerry Coffin的回答为您提供了一种从长远来看对您更有效的替代方法。首先,您不能强制引用基类的后代。 您需要使用指向该类型的指针,并使用
dynamic\u cast
所以,你有
EventSender sender (handler);
在main()
中。sender
的构造函数绑定到MyHandler
的基类EventHandler
,因为这是MyHandler
的构造函数中的参数类型(=EventHandler::EventHandler
)。因此,调用了EventHandler.Esr(const-Event&)
,它恰好是虚拟的,因此有一个指向MyHandler.Esr(const-Event&)
的指针
请注意,从技术上讲,
Esr(const-Event&)
和Esr(const-specialvent&)
是两种不同的方法;它们恰好使用了相同的名称。这里您尝试使用重载,而不是经典的(基于虚拟函数的)多态性
你想要的(至少据我所知)是直接使用处理程序
和通过发送方
间接调用它之间本质上相同的行为。发生的变化在事件
和特殊事件
之间
在这种情况下,经典多态性将涉及事件中的一个虚拟函数,该函数在SpecialEvent
中被重写:
struct Event {
virtual void operator()() const { std::cout << "Event\n"; }
};
struct SpecialEvent : public Event {
virtual void operator()() const override { std::cout << "Special Event\n"; }
};
不确定这是否与问题有关,但为什么要将事件实例传递给SendEvent
,然后在SendEvent
中忽略此参数,但将新的event
实例传递给Esr
?解决此类问题的正确工具是调试器。在询问堆栈溢出之前,应该逐行检查代码。如需更多帮助,请阅读。至少,您应该[编辑]您的问题,以包括一个重现您的问题的示例,以及您在调试器中所做的观察。一个有趣的问题:一步走向答案,但不是完整答案,因此需要注释:通过替换{}is=0,使Esr方法纯虚拟;在方法声明中。@πάνταῥεῖ 您希望他在调试器中看到哪些尚未发现的内容?他很好地确定了实际调用的方法。现在他在问“为什么?”我想你把多态性和重载混为一谈了。
#include <iostream>
struct Event {
virtual void operator()() const { std::cout << "Event\n"; }
};
struct EventHandler {
void Esr(const Event& I) const { I(); }
};
struct EventSender {
template <typename T>
void SendEvent (const T& t) const {
handler.Esr(t);
}
EventHandler handler;
};
struct SpecialEvent : public Event {
virtual void operator()() const override { std::cout << "Special Event\n"; }
};
int main() {
EventHandler handler;
EventSender sender;
/* Invoke directly */
handler.Esr (Event ());
handler.Esr (SpecialEvent ());
/* Invoke indirectly */
sender.SendEvent (Event ());
sender.SendEvent (SpecialEvent ()); // Expected cout msg: "SpecialEvent"
}