我目前正在为我的游戏引擎开发一个事件系统。我想过两种方法可以实现它:
1. 带继承:
class Event
{
//...
Type type; // Event type stored using an enum class
}
class KeyEvent : public Event
{
int keyCode = 0;
//...
}
2. 与 union :
class Event
{
struct KeyEvent
{
int keyCode = 0;
//...
}
Type type; // Event type stored using an enum class
union {
KeyEvent keyEvent;
MouseButtonEvent mouseButtonEvent;
//...
}
}
在这两种情况下,您都必须检查
Event::Type
枚举,以了解发生了哪种事件。当您使用继承时,您必须强制转换事件以获取它的值(例如,将
Event
转换为 KeyPressedEvent
以获取关键代码)。所以你必须将原始指针转换为需要的类型,这通常很容易出错。当您使用 union 时,您可以简单地检索已发生的事件。但这也意味着内存中 union 的大小总是与其中包含的最大可能类一样大。这意味着可能会浪费大量内存。
现在的问题:
是否有任何论据可以使用一种方式而不是另一种方式?我应该浪费内存还是冒着错误转换的风险?
或者有没有我没有想到的更好的解决方案?
最后我只想通过例如一个
KeyEvent
作为 Event
.然后我想查看Event::Type
使用枚举类。如果类型等于 Event::Type::Key
我想获取关键事件的数据。
最佳答案
Event
似乎比以行为为中心更以数据为中心,所以我会选择 std::variant
:
using Event = std::variant<KeyEvent, MouseButtonEvent/*, ...*/>;
// or using Event = std::variant<std::unique_ptr<KeyEvent>, std::unique_ptr<MouseButtonEvent>/*, ...*/>;
// In you are concerned to the size... at the price of extra indirection+allocation
那么用法可能类似于
void Print(const KeyEvent& ev)
{
std::cout << "KeyEvent: " << ev.key << std::endl;
}
void Print(const MouseButtonEvent& ev)
{
std::cout << "MouseButtonEvent: " << ev.button << std::endl;
}
// ...
void Print_Dispatch(const Event& ev)
{
std::visit([](const auto& ev) { return Print(ev); }, ev);
}
关于c++ - 事件系统 : Inheritance with type-casting or unions,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62044850/