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

发布于 2024-12-05 03:39:57 字数 1508 浏览 0 评论 0原文

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

提前感谢您的指点!我有点坚持这个。

I'm trying to create an event system with notifications via callbacks. I have the code written, but it is dependent on void pointers to work. After how hard void pointers bit me in my last project I would like to replace the void pointers with something that compile time type checks.

Here's the Event class

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

And here's the code to test the Event class

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

Thanks in advance for any pointers! I'm kinda stuck on this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

我不在是我 2024-12-12 03:39:57

让我们应用模板:

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

Let's apply templates:

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);
       }
    }
};
扛刀软妹 2024-12-12 03:39:57

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

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

This can be done with templates, but it would need quite a rework. Start by templating EventHandler by the kind of data to store, and create some common base EventHandlerBase class. For register and send event to do type checks you'll have to drop the enums and move to some typed kind of event id, so you can call registerForEvent< TEST_TYPE_A >( &handle ) and sendEvent< TEST_TYPE_A >( whatever_type_this_is ).

You could have test types be defined as structs with a nested typedef declaration for the type of data. But then you have missed the ability to distinguish between event types at run-time. You will need to generate some unique value for each event-type type, like the result of typeid.

叫思念不要吵 2024-12-12 03:39:57

基本上,要从 EventHandler 中删除 void*,您必须模板化 EventHandler,从而模板化 Event。这听起来很不高兴,直到您意识到每个 EventType 应该接收相同的参数类型,对吗?如果没有,那么您可能还有其他问题。因此,您将为 MouseEvent 提供一个 Event 类,为 KeyboardEvent 提供一个 Event 类,无论如何,这是有意义的,因为它们来自不同的来源。唯一的问题是,现在您无法拥有一个接收或查看所有事件的函数,除非它也是模板化的。

Basically, to remove void* from EventHandler, you'll have to template EventHandler, and thus Event. This sounds unhappy, until you realize that each EventType should be receiving the same parameter type, right? If not, then you probably have other problems. So you'll have one Event class for MouseEvents and one Event for KeyboardEvents, which makes sense anyway, since they come from different sources. The only problem is now you can't have a single function that receives or peeks at all events, unless it's also templated.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文