如何用在此回调中具有编译时类型检查的内容替换void指针?

时间:2011-09-15 22:09:19

标签: c++ templates polymorphism void-pointers

我正在尝试通过回调创建一个包含通知的事件系统。我编写了代码,但它依赖于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;
}

提前感谢任何指针!我有点坚持这个。

3 个答案:

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