Я внедряю систему событий для игры. Он использует очередь событий и структуру данных для хранения всех зарегистрированных обработчиков событий для данного типа события. До сих пор она работала нормально, регистрируя обработчики, но когда дело доходит до отмены их регистрации (что происходит, например, при уничтожении игрового объекта), у меня возникают небольшие проблемы с шаблонами и приведением типов.
Я определил EventHandler как своего рода функтор, частично основанный на статье Шимона Гатнера о http://www.gamedev.net/reference/programming/features/effeventcpp/. Чтобы быть точным, я взял определения классов HandlerFunctionBase и MemberFunctionHandler и придумал:
class BaseEventHandler
{
public:
virtual ~BaseEventHandler(){}
void handleEvent(const EventPtr evt)
{
invoke(evt);
}
private:
virtual void invoke(const EventPtr evt)=0;
};
template <class T, class TEvent>
class EventHandler: public BaseEventHandler
{
public:
typedef void (T::*TMemberFunction)(boost::shared_ptr<TEvent>);
typedef boost::shared_ptr<T> TPtr;
typedef boost::shared_ptr<TEvent> TEventPtr;
EventHandler(TPtr instance, TMemberFunction memFn) : mInstance(instance), mCallback(memFn) {}
void invoke(const EventPtr evt)
{
(mInstance.get()->*mCallback)(boost::dynamic_pointer_cast<TEvent>(evt));
}
TPtr getInstance() const{return mInstance;}
TMemberFunction getCallback() const{return mCallback;}
private:
TPtr mInstance;
TMemberFunction mCallback;
};
Тогда начальная реализация метода unregisterHandler () в классе EventManager, о котором я думал, будет выглядеть так:
// EventHandlerPtr is a boost::shared_ptr<BaseEventHandler>.
// mEventHandlers is an STL map indexed by TEventType, where the values are a std::list<EventHandlerPtr>
void EventManager::unregisterHandler(EventHandlerPtr hdl,TEventType evtType)
{
if (!mEventHandlers.empty() && mEventHandlers.count(evtType))
{
mEventHandlers[evtType].remove(hdl);
//remove entry if there are no more handlers subscribed for the event type
if (mEventHandlers[evtType].size()==0)
mEventHandlers.erase(evtType);
}
}
Чтобы здесь работало «удалить», я подумал о перегрузке оператора == для BaseEventHandler, а затем об использовании виртуального метода для фактического сравнения ...
bool BaseEventHandler::operator== (const BaseEventHandler& other) const
{
if (typeid(*this)!=typeid(other)) return false;
return equal(other);
}
и, в классе шаблона EventHandler, реализуйте абстрактный метод «равный» следующим образом:
bool equal(const BaseEventHandler& other) const
{
EventHandler<T,TEvent> derivedOther = static_cast<EventHandler<T,TEvent>>(other);
return derivedOther.getInstance() == this->getInstance() && derivedOther.getCallback()==this->getCallback();
}
Конечно, я получаю ошибку компиляции в строке static_cast. Я даже не уверен, что это вообще возможно сделать (не обязательно используя static_cast). Есть ли способ выполнить это, или хотя бы какой-нибудь обходной путь, который делает трюк?
Заранее спасибо =)