C++ 选择基于方法的参数的动态类型
C++ choose method based argument's dynamic type
问题
假设我有一些模拟器库,它从我那里获取一些对象(也称为事件处理程序)并通过调用它们的 handle_event(Event)
方法为这些对象生成事件。图书馆为我提供了以下 classes:
class Event {}; // Base class for all events
// All event classes are derived from `Event`
class SomeParticularEvent : public Event {}; // Some event class
class AnotherParticularEvent : public Event {}; // Some event class
// Object aka event handler. I should inherit this class and then give objects to the simulator
class AbstractEventHandler
{
public:
virtual void handle_event(Event) = 0;
};
我想实现一个以不同方式处理不同事件的对象。我想出的第一个代码如下:
#include <iostream>
class MyObject : public AbstractEventHandler
{
public:
void actual_handle_event(SomeParticularEvent)
{
std::cout << "`SomeParticularEvent` occurred\n";
}
void actual_handle_event(AnotherParticularEvent)
{
std::cout << "`AnotherParticularEvent` occurred\n";
}
void actual_handle_event(Event e)
{
std::cerr << "Unknown event type occurred\n";
}
virtual void handle_event(Event e) override
{
actual_handle_event(e);
}
};
与我的预期相反,MyObject::handle_event(Event)
将始终调用 MyObject::actual_handle_event(Event)
,而不管 e
.
的动态类型如何
我的问题是:实施 MyObject
的正确方法是什么(最好是能够轻松添加新的事件类型)?
所有代码一起
#include <iostream>
class Event {}; // Base class for all events
// All event classes are derived from `Event`
class SomeParticularEvent : public Event {}; // Some event class
class AnotherParticularEvent : public Event {}; // Some event class
class AbstractEventHandler
{
public:
virtual void handle_event(Event) = 0;
};
class MyObject : public AbstractEventHandler
{
public:
void actual_handle_event(SomeParticularEvent)
{
std::cout << "`SomeParticularEvent` occurred\n";
}
void actual_handle_event(AnotherParticularEvent)
{
std::cout << "`AnotherParticularEvent` occurred\n";
}
void actual_handle_event(Event e)
{
std::cerr << "Unknown event type occurred\n";
}
virtual void handle_event(Event e) override
{
actual_handle_event(e);
}
};
int main()
{
MyObject o{};
o.handle_event(SomeParticularEvent{}); // Prints "Unknown event type occurred"
}
附加问题
是否也可以创建一个从 MyObject
派生的 class 并实现 额外的 事件处理程序(不覆盖旧的,但添加对新的支持事件)而不重写派生的 class?
中的 handle_event
方法
在您的方法中 handle_event()
发生对象切片。您应该传递 (const) 引用以使继承正常工作,或者传递指针。
但是,当从 handle_event()
内部调度到 actual_handle_event()
时,这对您的情况没有帮助。
一个蛮力解决方案是通过尝试 dynamic_casts
来显式调度。您需要在派生 类 中覆盖 handle_event()
以扩展它。它看起来也不那么漂亮(表明设计问题)。
在这些情况下通常所做的是,所讨论的对象 (Event
) 将提供一个接口来查询类型,例如被覆盖的抽象 type()
getter。
根据问题中的要求和@ypnos answer 的评论中讨论的内容,我相信您希望或需要在此处实现访问者模式。
一种可能的实现如下所示(基于关于访问者模式的维基百科文章:https://en.wikipedia.org/wiki/Visitor_pattern#C++_example)
#include <iostream>
// Forward declare all Event classes
class Event;
class SomeParticularEvent;
class AnotherParticularEvent;
class AbstractEventHandler
{
public:
virtual void handle_event(const Event&) = 0;
virtual void handle_event(const SomeParticularEvent&) = 0;
virtual void handle_event(const AnotherParticularEvent&) = 0;
};
class Event {
public:
// virtual function for accepting the "visitor"
virtual void accept(AbstractEventHandler& handler) {
handler.handle_event(*this);
}
}; // Base class for all events
// All event classes are derived from `Event`
class SomeParticularEvent : public Event {
public:
// Needs to be overriden to call `handle_event` with the correct type
void accept(AbstractEventHandler& handler) override {
handler.handle_event(*this);
}
}; // Some event class
class AnotherParticularEvent : public Event {
public:
void accept(AbstractEventHandler& handler) override {
handler.handle_event(*this);
}
}; // Some event class
class MyObject : public AbstractEventHandler
{
public:
void handle_event(const SomeParticularEvent&) override
{
std::cout << "`SomeParticularEvent` occurred\n";
}
void handle_event(const AnotherParticularEvent&) override
{
std::cout << "`AnotherParticularEvent` occurred\n";
}
void handle_event(const Event& e) override
{
std::cerr << "Unknown event type occurred\n";
}
};
int main()
{
MyObject o{};
SomeParticularEvent{}.accept(o);
AnotherParticularEvent{}.accept(o);
}
问题
假设我有一些模拟器库,它从我那里获取一些对象(也称为事件处理程序)并通过调用它们的 handle_event(Event)
方法为这些对象生成事件。图书馆为我提供了以下 classes:
class Event {}; // Base class for all events
// All event classes are derived from `Event`
class SomeParticularEvent : public Event {}; // Some event class
class AnotherParticularEvent : public Event {}; // Some event class
// Object aka event handler. I should inherit this class and then give objects to the simulator
class AbstractEventHandler
{
public:
virtual void handle_event(Event) = 0;
};
我想实现一个以不同方式处理不同事件的对象。我想出的第一个代码如下:
#include <iostream>
class MyObject : public AbstractEventHandler
{
public:
void actual_handle_event(SomeParticularEvent)
{
std::cout << "`SomeParticularEvent` occurred\n";
}
void actual_handle_event(AnotherParticularEvent)
{
std::cout << "`AnotherParticularEvent` occurred\n";
}
void actual_handle_event(Event e)
{
std::cerr << "Unknown event type occurred\n";
}
virtual void handle_event(Event e) override
{
actual_handle_event(e);
}
};
与我的预期相反,MyObject::handle_event(Event)
将始终调用 MyObject::actual_handle_event(Event)
,而不管 e
.
我的问题是:实施 MyObject
的正确方法是什么(最好是能够轻松添加新的事件类型)?
所有代码一起
#include <iostream>
class Event {}; // Base class for all events
// All event classes are derived from `Event`
class SomeParticularEvent : public Event {}; // Some event class
class AnotherParticularEvent : public Event {}; // Some event class
class AbstractEventHandler
{
public:
virtual void handle_event(Event) = 0;
};
class MyObject : public AbstractEventHandler
{
public:
void actual_handle_event(SomeParticularEvent)
{
std::cout << "`SomeParticularEvent` occurred\n";
}
void actual_handle_event(AnotherParticularEvent)
{
std::cout << "`AnotherParticularEvent` occurred\n";
}
void actual_handle_event(Event e)
{
std::cerr << "Unknown event type occurred\n";
}
virtual void handle_event(Event e) override
{
actual_handle_event(e);
}
};
int main()
{
MyObject o{};
o.handle_event(SomeParticularEvent{}); // Prints "Unknown event type occurred"
}
附加问题
是否也可以创建一个从 MyObject
派生的 class 并实现 额外的 事件处理程序(不覆盖旧的,但添加对新的支持事件)而不重写派生的 class?
handle_event
方法
在您的方法中 handle_event()
发生对象切片。您应该传递 (const) 引用以使继承正常工作,或者传递指针。
但是,当从 handle_event()
内部调度到 actual_handle_event()
时,这对您的情况没有帮助。
一个蛮力解决方案是通过尝试 dynamic_casts
来显式调度。您需要在派生 类 中覆盖 handle_event()
以扩展它。它看起来也不那么漂亮(表明设计问题)。
在这些情况下通常所做的是,所讨论的对象 (Event
) 将提供一个接口来查询类型,例如被覆盖的抽象 type()
getter。
根据问题中的要求和@ypnos answer 的评论中讨论的内容,我相信您希望或需要在此处实现访问者模式。
一种可能的实现如下所示(基于关于访问者模式的维基百科文章:https://en.wikipedia.org/wiki/Visitor_pattern#C++_example)
#include <iostream>
// Forward declare all Event classes
class Event;
class SomeParticularEvent;
class AnotherParticularEvent;
class AbstractEventHandler
{
public:
virtual void handle_event(const Event&) = 0;
virtual void handle_event(const SomeParticularEvent&) = 0;
virtual void handle_event(const AnotherParticularEvent&) = 0;
};
class Event {
public:
// virtual function for accepting the "visitor"
virtual void accept(AbstractEventHandler& handler) {
handler.handle_event(*this);
}
}; // Base class for all events
// All event classes are derived from `Event`
class SomeParticularEvent : public Event {
public:
// Needs to be overriden to call `handle_event` with the correct type
void accept(AbstractEventHandler& handler) override {
handler.handle_event(*this);
}
}; // Some event class
class AnotherParticularEvent : public Event {
public:
void accept(AbstractEventHandler& handler) override {
handler.handle_event(*this);
}
}; // Some event class
class MyObject : public AbstractEventHandler
{
public:
void handle_event(const SomeParticularEvent&) override
{
std::cout << "`SomeParticularEvent` occurred\n";
}
void handle_event(const AnotherParticularEvent&) override
{
std::cout << "`AnotherParticularEvent` occurred\n";
}
void handle_event(const Event& e) override
{
std::cerr << "Unknown event type occurred\n";
}
};
int main()
{
MyObject o{};
SomeParticularEvent{}.accept(o);
AnotherParticularEvent{}.accept(o);
}