Sto implementando un sistema di eventi per un gioco. Utilizza una coda eventi e una struttura dati per contenere tutti i gestori di eventi registrati per un determinato tipo di evento. Funziona bene fino ad ora registrare i gestori, ma quando si tratta di annullare la registrazione (qualcosa che si verificherà quando un oggetto di gioco viene distrutto, ad esempio) ho un po 'di problemi per quanto riguarda i modelli e il casting.Downcasting della classe base non-template alla classe derivata basata su modelli: è possibile?
ho definito un EventHandler come una sorta di funtore, in parte sulla base di un articolo di Szymon Gatner su http://www.gamedev.net/reference/programming/features/effeventcpp/. Per essere precisi, ho preso le definizioni HandlerFunctionBase e MemberFunctionHandler di classe e si avvicinò 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;
};
Poi l'implementazione iniziale per il metodo unregisterHandler() sulla classe EventManager Ho pensato sarebbe andata in questo modo:
// 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);
}
}
di fare "Rimuovi" lavoro qui ho pensato di sovraccaricare l'operatore == per BaseEventHandler, e quindi utilizzando un metodo virtuale per eseguire il confronto vero e proprio ...
bool BaseEventHandler::operator== (const BaseEventHandler& other) const
{
if (typeid(*this)!=typeid(other)) return false;
return equal(other);
}
e, sulla EventHandler classe template, implementare il metodo astratto 'uguale' come questo:
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();
}
Naturalmente, sto ottenendo un errore di compilazione sulla linea static_cast. Non sono nemmeno sicuro che sia possibile fare quel cast (non necessariamente usando static_cast). C'è un modo per farlo, o almeno qualche soluzione che fa il trucco?
Grazie in anticipo =)
È possibile eseguire il cast di almeno un tipo di riferimento piuttosto che 'derivedOther' cercando di essere una * copia * del parametro" altro ". Temo che la tua domanda sia troppo lunga per consentirmi di capire a fondo proprio in questo momento, quindi non sono sicuro che si tratti di un problema secondario o della risposta giusta. Consiglio generale: ricorda che due diverse classi EventHandler con diversi parametri del modello non sono correlate, ma sono state create con la stessa fonte. Non esiste un tipo come "EventHandler" a meno che non siano specificati T e TEvent, quindi "altro" sarebbe meglio avere la stessa classe di "questo". –
Dovresti includere l'errore di compilazione che ottieni. Un'altra nota: esiste una ragione per cui 'equal()' non è dichiarato nella classe template 'EventHandler'? –