我正在尝试通过回调创建一个包含通知的事件系统。我编写了代码,但它依赖于void指针才能工作。在我的上一个项目中有多少硬指针指向我之后,我想用编译时间类型检查的东西替换void指针。
这是Event类
enum EventType {
TEST_TYPE_A,
TEST_TYPE_B
};
// used by event receivers
class EventHandler
{
public:
virtual void handleEvent(EventType type, void* data) = 0; // PROBLEM HERE
};
// class to send events to objects registered for them
class Event
{
private:
std::multimap<EventType, EventHandler*> eventMap;
public:
void registerForEvent(EventType type, EventHandler *handler) {
eventMap.insert(std::pair<EventType, EventHandler*>(type, handler));
}
void sendEvent(EventType type, void* data) { // PROBLEM HERE
std::multimap<EventType, EventHandler*>::iterator it;
std::pair<std::multimap<EventType, EventHandler*>::iterator, std::multimap<EventType, EventHandler*>::iterator> matches;
matches = eventMap.equal_range(type);
for (it = matches.first; it != matches.second; ++it) {
it->second->handleEvent(type, data);
}
}
};
这是测试Event类的代码
class Handler : public EventHandler {
public:
void handleEvent(EventType type, void* data) {
char *cp = (char*)data;
printf("Handler: %s \n", cp);
}
};
int main(int argc, const char* argv[]) {
Handler handle;
Event event;
char c[] = "what?";
event.registerForEvent(TEST_TYPE_A, &handle);
event.sendEvent(TEST_TYPE_A, (void*)c);
return 0;
}
提前感谢任何指针!我有点坚持这个。
答案 0 :(得分:2)
基本上,要从void*
移除EventHandler
,您必须模板EventHandler
,因此Event
。这听起来不开心,直到你意识到每个EventType
应该接收相同的参数类型,对吧?如果没有,那么你可能还有其他问题。因此,Event
的{{1}}课程和MouseEvent
的{{1}}课程有一个Event
,无论如何都是有道理的,因为它们来自不同的来源。唯一的问题是现在你不能拥有接收或查看所有事件的单一函数,除非它也是模板化的。
答案 1 :(得分:2)
这可以通过模板完成,但需要进行大量的返工。首先将EventHandler
模板化为要存储的数据类型,然后创建一些公共基础EventHandlerBase
类。要注册和发送事件以进行类型检查,您必须删除枚举并转到某种类型的事件ID,这样您就可以拨打registerForEvent< TEST_TYPE_A >( &handle )
和sendEvent< TEST_TYPE_A >( whatever_type_this_is )
。
您可以将测试类型定义为具有数据类型的嵌套typedef声明的结构。但是你错过了在运行时区分事件类型的能力。您需要为每种事件类型类型生成一些唯一值,例如typeid
的结果。
答案 2 :(得分:2)
让我们应用模板:
enum EventType {
TEST_TYPE_A,
TEST_TYPE_B
};
template <EventType> class EventData {};
template <> class EventData<TEST_TYPE_A> { /*****/ };
template <> class EventData<TEST_TYPE_B> { /*****/ };
// used by event receivers
class EventHandlerBase { public: virtual ~EventHandlerBase() { } };
template <EventType ET> class EventHandler : public EventHandlerBase
{
public:
virtual void handleEvent(EventData<ET> const& data) = 0;
};
class EventDispatcherBase { // Shared logic
protected:
std::set<std::shared_ptr<EventHandlerBase>> handlers;
void addHandler(std::shared_ptr<EventHandlerBase>);
void removeHandler(EventHandlerBase&);
};
typename <EventType ET> class EventDispatcher : private EventDispatcherBase {
public:
using EventDispatcherBase::addHandler;
using EventDispatcherBase::removeHandler;
void dispatchEvent(EventData<ET>& data) {
for (std::shared_ptr<EventHandlerBase> ptr : handlers) {
dynamic_cast<EventHandler<ET>&>(*ptr).handleEvent(data);
}
}
};