我如何用在这个回调中具有编译时类型检查的东西替换void指针?

How can I replace the void pointer with something that has compile time type checks in this callback?

本文关键字:检查 类型 替换 指针 void 编译 何用 回调      更新时间:2023-10-16

我试图通过回调创建一个带有通知的事件系统。我写的代码,但它是依赖于空指针的工作。在我的上一个项目中,我想用编译时类型检查取代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;
}

提前感谢任何指示!我有点卡住了

让我们应用模板:

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);
       }
    }
};

这可以用模板完成,但需要大量的返工。首先根据要存储的数据类型对EventHandler进行模板化,并创建一些通用的基础EventHandlerBase类。对于注册和发送事件进行类型检查,您必须放弃枚举并移动到某些类型的事件id,因此您可以调用registerForEvent< TEST_TYPE_A >( &handle )sendEvent< TEST_TYPE_A >( whatever_type_this_is )

您可以将测试类型定义为具有数据类型的嵌套类型定义声明的结构体。但是,这样就错过了在运行时区分事件类型的能力。您需要为每个事件类型类型生成一些惟一的值,就像typeid的结果一样。

基本上,要从EventHandler中删除void*,您必须模板EventHandler,因此Event。这听起来令人不快,直到您意识到每个EventType应该接收相同的参数类型,对吗?如果不是,那么你可能有其他问题。因此,您将为MouseEvent s提供一个Event类,为KeyboardEvent s提供一个Event类,这是有意义的,因为它们来自不同的来源。唯一的问题是现在你不能有一个函数接收或窥视所有事件,除非它也被模板化。