我目前正在为C ++中的游戏编写事件传递系统,我认为如果事件以逻辑方式相互继承,那将会很有用。
这意味着我可以例如引发类型为NukeExplosion
的事件,该事件派生自Explosion
(可能来自空基类Event
)并且它将被传递给所有类型为NukeExplosion
的事件的听众,以及更通用的Explosion
。
到目前为止,我能够提出两种可能的解决方案:
dynamic_cast
。如果成功,我可以将事件传递给集合中的所有侦听器。typeid
运算符的结果和侦听器映射将事件传递给侦听器。我真的不喜欢第二个选项,因为它容易出错,并且要求我在每个事件类中编写几乎相同的代码。
第一个选项的问题是它可能需要做很多dynamic_cast
,我想避免这种情况。
那么,有没有其他方法我没有考虑到accont,或者是我能做的第一个选择?或者我应该完全放弃事件的继承?
答案 0 :(得分:1)
我几乎就是这个问题来到这里的。问题基本上是,即使handle (ExplosionEvent *e)
的动态类型为{{1},C ++也不会让像e
这样的函数接受带有静态类型Event *
的参数e
。 }。这将是一个很好的功能,但我不太确定还有什么必须改变语言。
访客模式是我能想到的最干净的解决方案。缺点是它很冗长,而且可能不比ExplosionEvent *
便宜。
Main.hpp:
dynamic_cast<>
Event.hpp:
#include <iostream>
class Event;
class Handler;
#include "Event.hpp"
#include "Handler.hpp"
Event.cpp:
#ifndef EVENT_H
#define EVENT_H
class Event
{
public:
virtual void accept (Handler *handler) { }
};
class ExplosionEvent : public Event
{
void accept (Handler *handler);
};
#endif // !EVENT_H
Handler.hpp:
#include "Main.hpp"
void
ExplosionEvent::accept (Handler *handler)
{
handler->handleExplosion (this);
}
Handler.cpp:
#ifndef HANDLER_H
#define HANDLER_H
class Handler
{
public:
void handle (Event *event) { event->accept (this); }
virtual void handleExplosion (ExplosionEvent *explosionEvent) { }
};
class ExplosionHandler : public Handler
{
void handleExplosion (ExplosionEvent *explosionEvent);
};
#endif // !HANDLER_H
Main.cpp的:
#include "Main.hpp"
void
ExplosionHandler::handleExplosion (ExplosionEvent *explosionEvent)
{
std::cout << "BOOM!" << std::endl;
}
编译并运行:
#include "Main.hpp"
int
main (int argc, char *args)
{
Event *event = new ExplosionEvent;
Handler *handler = new ExplosionHandler;
handler->handle (event);
}
答案 1 :(得分:0)
为每个侦听器执行动态转换对于大量侦听器来说会非常昂贵,因此您可能不得不为侦听器实现一个typeid映射。
我的听众会有一个HandleEvent
,它会占用Event
个对象。此方法将(使用static_cast
)基本事件转换为它期望的事件类型(它需要信任事件注册机制的事件调度程序)。
我还会在Event
类中实现一个方法,该方法会返回一个新的基本事件(如果有效),因为您可能不想发送基类Event
。这可以用宏来完成,但我觉得它也可以用模板方法完成,虽然我还没能使它工作。然后,调度程序将在调用事件处理程序之前获取该基本事件,然后调用处理程序以获取基本事件。