CallBack auf Methode von Child
-
Moin, moin,
ich möchte einer Methode Pointer auf Methoden deren Childklassen übergeben. Dabei können mehrere Generation von Childklassen existieren.
Bisher habe ich das durch Casten der Methoden auf die Hauptklasse erreicht, was aber das Händling unschön macht.class IchRufeDieMethodenAuf; typefed void(IchRufeDieMethodenAuf::*TCallBack)(); class IchRufeDieMethodenAuf { protected : void addCallBack( int id, TCallBack callBackPointer) { this->callBackMap[id] = callBackPointer; } private : void callCallBack( int id ) { ( this->*(this->callBackMap[id]) )(); } std::map<int, TCallBack> callBackMap; } class IchHabeDieMethoden : public IchRufeDieMethodenAuf { public : IchHabeDieMethoden() { this->addCallBack( 100, static_cast< TCallBack >( &IchHabeDieMethoden::callBack100 ) ); } private : callBack100(); }Der Methodenpointer auf IchHabeDieMethoden::callBack100() zeigt nach dem Typecast eigentlich auf etwas undefiniertes, da es ein IchRufeDieMethodenAuf::callBack100() ja nicht gibt. Erst mein Aufrufen ergibt der Pointer wieder einen Sinn, weil this vom Typ IchHabeDieMethoden ist.
Ich würde gerne den Aufruf der add-Methode verwandeln in:
this->addCallBack( 100, &IchHabeDieMethoden::callBack100 );Bei boost:function muss man explicit den Typ vorher angeben, was mich auch nicht weiter bringt, da ich in IchRufeDieMethodenAuf die Childklassen noch nicht kenne.
Ein Template hilft nicht viel weiter, da alle Generation callBacks hinzufügen können.cu
Martin
-
Thundernail schrieb:
Ein Template hilft nicht viel weiter, da alle Generation callBacks hinzufügen können.
Was geht da nicht?
protected : template<typename T> void addCallBack( int id, void(T::*callbackPointer)()) { addCallBackImpl( id, static_cast< TCallBack >( callbackPointer ) ); } private: void addCallBackImpl( int id, TCallBack callBackPointer) { this->callBackMap[id] = callBackPointer; }
-
ich glaube so, wie du dir das denkst, geht das nicht, mit der polymorphie, also nicht schön.
Das Problem ist, dass dein Basisobjekt ein Callback machen soll auf eine Methode, die es gar nicht kennt. du rufst also über die Basis eine Methode auf, die auf alle Fälle als this-pointer ein abgeleitetes objekt erwartet. Das ist gefährlich, denn was ist, wenn this mal grade nicht so ein objekt sondern wirklich eins der basisklasse ist:
int main() { IchRufeDieMethodenAuf a; IchHabeDieMethoden b; a.addcallback(100, b::callBack100); a.callcallback(100); // hier knallts. }Ich weiß, das Beispiel is weit hergeholt, hab jetzt auch nich auf private geachtet und so, aber das könnte so passieren.
Das ganze scheint nach dem observerpattern auszusehen. Warum soll eine abgeleitete Klasse überhaupt bei ihrem papa Callbacks registrieren? Könnte auch schon ein genereller Designfehler sein.
Beschreib mal was du damit vorhast, vielleicht kann man da ne bessere Lösung finden. Kannst dir ja mal boost::signals anschauen, damit könnte das gehen.
-
Moin, moin,
@camper: :-), so hatte ich den Einsatz des Templates noch nicht bedacht (ich wollte dann auch die Liste vom Typ abhängig machen). Danke.
@Maxi: addcallback() ist protected, deshalb funtioniert Dein Beispiel nicht. Und es können nur Methoden von Verwanten Klassen übergeben werden. Ansonsten Schmeißt der static_cast bei kompilieren Fehler. Einzig könnte jemand in IchHabeDieMethoden1 ein Object von IchHabeDieMethoden2 erzeugen und dass dann übergeben :-(. Der Fall sollte aber eigentlich nicht vorkommen.
Zur Anwendung: Es handelt sich dabei um packetorientierte Kommunikation zwischen Komponenten. Komponenten können auf Prozesse verteilt sein (InterProzessCommunication). Eine Komponente kommuniziert grundsätzlich nur über die Packete und hat nach aussen (public) nur den Konstruktor/Destructor und eine poll-Funktion, die das Abrufen der Packete startet.
Eine Komponente muss sich, wenn sie ein Packettyp empfangen will, auf dessen Id anmelden. Wenn ein Packet ankommt, soll die dazugehörige Methode aufgerufen werden, um es zu verarbeiten. Verarbeiten heißt in der Regel die Daten zu speichern ggf. auf schon gespeicherte Daten (anderer Packete) zurückgreifen und neue Packete versenden.Struckturell bestehen die Komponenten aus einer Klasse die von IchRufeDieMethodenAuf abgeleitet wurde.
Ich hoffe, dass ist irgendwie Verständlich
Martin