Estoy implementando un sistema de eventos para un juego. Utiliza una cola de eventos y una estructura de datos para contener todos los controladores de eventos registrados para un tipo de evento determinado. Hasta ahora funciona bien registrando controladores, pero cuando se trata de anular el registro (algo que sucederá cuando se destruye un objeto de juego, por ejemplo) tengo problemas con las plantillas y el molde.Downcasting clase base no de plantilla a clase derivada de plantilla: ¿es posible?
He definido un manejador de eventos como un tipo de functor, parcialmente basado en el artículo de Szymon Gatner en http://www.gamedev.net/reference/programming/features/effeventcpp/. Para ser precisos, tomé las definiciones de clase y HandlerFunctionBase MemberFunctionHandler y se acercó con:
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;
};
A continuación, la aplicación inicial del método unregisterHandler() en la clase EventManager he pensado iría así:
// 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);
}
}
para hacer "eliminar" trabajo aquí pensé de sobrecargar el operador == para BaseEventHandler, y luego usando un método virtual para realizar la comparación real ...
bool BaseEventHandler::operator== (const BaseEventHandler& other) const
{
if (typeid(*this)!=typeid(other)) return false;
return equal(other);
}
y, por el manejador de sucesos clase de plantilla, implementar el método abstracto 'igual' de esta manera:
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();
}
Por supuesto, estoy recibiendo un error de compilación en la línea static_cast. Ni siquiera estoy seguro de que sea posible hacer ese lanzamiento (no necesariamente usando static_cast). ¿Hay alguna manera de llevarlo a cabo, o al menos alguna solución alternativa que solucione el problema?
Gracias de antemano =)
Al menos podría convertir a un tipo de referencia en lugar de 'derivedOther' tratando de ser una * copia * del parámetro" otro ". Me temo que su pregunta es demasiado larga para que yo la entienda completamente en este momento, por lo que no estoy seguro de si esto es un problema secundario menor o la respuesta correcta. Consejo general: recuerde que dos clases diferentes de EventHandler con diferentes parámetros de plantilla no están relacionadas, sino que se crean con la misma fuente. No hay ningún tipo como 'EventHandler' a menos que se especifiquen T y TEvent, por lo que 'other' sería mejor que sea de la misma clase que' this'. –
Debe incluir el error de compilación que obtiene. Otra nota: ¿hay alguna razón por la cual 'igual()' no está declarado en la clase de plantilla 'EventHandler'? –