Как я могу заменить указатель void чем-то, что имеет проверку типов времени компиляции в этом обратном вызове? - PullRequest
2 голосов
/ 16 сентября 2011

Я пытаюсь создать систему событий с уведомлениями через обратные вызовы.У меня написан код, но он зависит от пустых указателей на работу.После того, как жесткие указатели 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 ]

2 голосов
/ 16 сентября 2011

Это можно сделать с помощью шаблонов, но для этого потребуется довольно доработка.Начните с шаблонирования EventHandler по типу данных для хранения и создайте некоторый общий базовый класс EventHandlerBase.Чтобы зарегистрировать и отправить событие для проверки типов, вам нужно отбросить перечисления и перейти к некоторому типу идентификатора события, чтобы вы могли вызывать registerForEvent< TEST_TYPE_A >( &handle ) и sendEvent< TEST_TYPE_A >( whatever_type_this_is ).

.быть определены как структуры с вложенным объявлением typedef для типа данных.Но тогда вы упустили возможность различать типы событий во время выполнения.Вам нужно будет сгенерировать уникальное значение для каждого типа типа события, например, результат typeid.

2 голосов
/ 16 сентября 2011

Давайте применим шаблоны:

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);
       }
    }
};
2 голосов
/ 16 сентября 2011

Как правило, чтобы удалить void* из EventHandler, вам необходимо создать шаблон EventHandler, и, таким образом, Event.Это звучит печально, пока вы не поймете, что каждый EventType должен получать один и тот же тип параметра, верно?Если нет, то у вас, вероятно, есть другие проблемы.Таким образом, у вас будет один Event класс для MouseEvent с и один Event для KeyboardEvent с, что в любом случае имеет смысл, поскольку они поступают из разных источников.Единственная проблема в том, что теперь у вас не может быть единственной функции, которая получает или просматривает все события, кроме случаев, когда она также шаблонизирована.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...