c++ - 事件系统:类型转换或联合的继承
问题描述
我目前正在为我的游戏引擎开发一个事件系统。我想过两种方法可以实现它:
1.带继承:
class Event
{
//...
Type type; // Event type stored using an enum class
}
class KeyEvent : public Event
{
int keyCode = 0;
//...
}
2.有工会:
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
以获取关键代码)。所以你必须将原始指针转换为需要的类型,这通常很容易出错。
当您使用联合时,您可以简单地检索已发生的事件。但这也意味着内存中联合的大小总是与其中包含的最大可能类一样大。这意味着可能会浪费大量内存。
现在的问题:
是否有任何论据可以使用一种方式而不是另一种方式?我应该浪费内存还是冒着错误投射的风险?
或者有没有我没有想到的更好的解决方案?
最后,我只想通过例如 aKeyEvent
作为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);
}
推荐阅读
- javascript - Socket.io 每 2 个连接创建一个对象
- python - 将 bfill 与所选数字一起使用
- python - 为什么我在尝试在 Keras 中构建具有多个输入的架构时会出错?
- excel - 查找并偏移以将值复制到第二个工作表的末尾
- java - HashMap 到 Json 数组对象 - Java
- java - C# 从 Java AES/CBC/PKCS5Padding 加密/解密
- docker - Docker 镜像名称自动更改
- mysql - 为什么我不能通过docker使用密码登录mysql服务器?
- algorithm - 卡在 Djikstra 算法上
- bash - 在 bash 中,脚本引用另一个脚本的路径的最佳方式是什么?