C ++ система для передачи событий с иерархией наследования - PullRequest
1 голос
/ 05 февраля 2012

В настоящее время я программирую систему передачи событий для игры на C ++, и я подумал, что было бы полезно, если бы события наследовали друг от друга логическим образом.

Это означает, что я могу, например, вызвать событие типа NukeExplosion, которое происходит от Explosion (которое, вероятно, будет происходить из пустого базового класса Event), и оно будет передано всем слушателямсобытие типа NukeExplosion, а также более общее Explosion.

До сих пор мне удавалось найти два возможных решения:

  • Выполнение dynamic_cast о событии для каждого набора слушателей одного и того же типа события.В случае успеха я могу передать событие всем слушателям в наборе.
  • Добавление фрагмента кода к каждому типу события, который снова вызывает событие, но с более общим типом.Затем событие будет передано слушателям, используя результат оператора typeid в сочетании с картой слушателей.

Мне не очень нравится второй вариант, потому что он подвержен ошибкам,и требует, чтобы я написал почти одинаковый код в каждом классе событий.

Проблема с первым вариантом заключается в том, что ему может потребоваться много dynamic_cast с, и я бы хотел этого избежать.

Итак, есть ли другой способ, которым яне приняли во внимание, или первый вариант - лучшее, что я могу сделать?Или мне полностью отказаться от наследования событий?

Ответы [ 2 ]

1 голос
/ 01 марта 2013

Я пришел сюда почти с этим вопросом.Проблема в основном в том, что C ++ не позволяет функции типа handle (ExplosionEvent *e) принимать аргумент e со статическим типом Event *, даже если динамический тип e равен ExplosionEvent *.Это было бы неплохо, но я не совсем уверен, что еще нужно изменить в языке.

Шаблон Visitor - самое чистое решение, которое я могу придумать.Недостатки в том, что он многословен и не может быть дешевле dynamic_cast<>.

Main.hpp:

#include <iostream>

class Event;
class Handler;

#include "Event.hpp"
#include "Handler.hpp"

Event.hpp:

#ifndef EVENT_H
#define EVENT_H

class Event 
{
public:
  virtual void accept (Handler *handler) { }
};

class ExplosionEvent : public Event 
{
  void accept (Handler *handler);
};

#endif // !EVENT_H

Event.cpp:

#include "Main.hpp"

void 
ExplosionEvent::accept (Handler *handler) 
{ 
  handler->handleExplosion (this);
}

Handler.hpp:

#ifndef HANDLER_H
#define HANDLER_H

class Handler
{
public:
  void handle (Event *event) { event->accept (this); }
  virtual void handleExplosion (ExplosionEvent *explosionEvent) { }
};

class ExplosionHandler : public Handler
{
  void handleExplosion (ExplosionEvent *explosionEvent);
};

#endif // !HANDLER_H

Handler.cpp:

#include "Main.hpp"

void
ExplosionHandler::handleExplosion (ExplosionEvent *explosionEvent)
{
  std::cout << "BOOM!" << std::endl;
}

Main.cpp:

#include "Main.hpp"

int
main (int argc, char *args)
{
  Event *event = new ExplosionEvent;
  Handler *handler = new ExplosionHandler;
  handler->handle (event);
}

Скомпилируйте и запустите:

$ g++ -o boom *.cpp
$ ./boom 
BOOM!
$ 
0 голосов
/ 06 февраля 2012

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

Мой слушатель будет иметь HandleEvent, который будет принимать Event объект. Этот метод приведёт (с static_cast) базовое событие к ожидаемому типу события (ему необходимо доверять диспетчеру событий для механизма регистрации событий).

Я бы также реализовал метод в классе Event, который бы возвращал новое базовое событие, если оно допустимо, поскольку вы, возможно, не захотите отправлять базовое Event. Это можно сделать с помощью макроса, но у меня есть ощущение, что это можно сделать и с помощью шаблонного метода, хотя я пока не смог заставить его работать. Затем диспетчер получит это базовое событие перед вызовом обработчиков событий, а затем вызовет обработчики для базового события.

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