Multiple Inheritance - Callbacks
-
Hallo, ich habe momentan bei einem Projekt ein Problem:
Ich hätte gerne eine abstrakte Basisklasse, bei der ich eine bestimmte Memberfuntkion aufrufe. Jede abgeleitet Klasse von ihr soll die Möglichkeit haben, ein Callback zu definieren, das dann in dieser Funktion aufgerufen wird. Das Problem ist, dass ich gerne virtual multiple inheritance nützen würde, d.h. dass das Callback jeder abgeleiteten Klasse genau einmal aufgerufen wird. Mit virtual functions habe ich bisher keine Möglichkeit gefunden, das zu implementieren (weil sich die virtual Functions immer überschreiben).
Stattdessen wollte ich es so versuchen, dass die Basisklasse einen std::vector auf Callbacks hat, dem im Konstruktor jeder abgeleiteten Klasse das jeweilige Callback hinzugefügt wird, in etwa so:class A { protected: std::vector< void (*)() > callbacks; public: void callFunctions() { for(auto it = callbacks.begin() ; it != callbacks.end() ; ++it) (*it)(); } }; class B : virtual public A { friend void callback() { std::cout<<"class B"<<std::endl; } public: B() { callbacks.push_back( callback ); } };Das ganze würde ich dann mit member functions machen und die this Pointer speichern, aber das ist hier ja nicht relevant.
Was mich an der Lösung stört, ist, dass die callbacks schon zu Compile Zeit fest stehen, und in jedem Objekt jetzt ein Vector voller Callbacks ist, was den Speicherbedarf dieser Klassen verdoppeln würde. Bis jetzt ist mir keine vernünftige Lösung eingefallen, allerdings hab ich auch nicht besonders viel Ahnung von template meta programming. Hat vielleicht ein c++ Veteran mit sowas Erfahrung/eine Idee?
Edit: Hab ich die Codetags falsch benutzt?
Mod-Edit: Nein, nur den BBCode im Beitrag ausgeschaltet
-
Mach deinen std::vector private und mache in deiner Basisklasse eine Funktion, mit der man ein Callback speichern kann.
Allerdings sieht hier Vererbung für mich als das falsche Mittel zum Zweck aus. Was hast du denn vor damit?
-
Ja, den Ansatz habe ich ja oben schon beschrieben, nur fände ich es Schade, wenn es tatsächlich nur diese Möglichkeit mit einem std::vector in jedem Objekt gibt. Da die callbacks schon zur compile Zeit feststehen, gibt es ja vielleicht eine Lösung mit template meta programming.
-
Was genau willst du denn damit bezwecken? Vermutlich gibts eine bessere Lösung.
-
Es geht um ein Spiel. In der Hauptschleife soll bei jedem Objekt callFunctions() aufgerufen werden.
Als Objekte hätte ich dann gerne sowas wieclass CreatureObject : virtual public MovingObject , virtual public HostileObject , virtual public DestructableObject , .... { .... };Ich brauche virtual inheritance, weil z.B. jedes Objekt eine Position hat, aber mehrere unabhängige Komponenten diese Wissen müssen, z.B. Wegfindung und Wahrnehmung (von anderen Objekten). Tiefer im Baum geht das natürlich so weiter.
-
Dafür würde ich eine eigene Klasse machen. "EventManager" von mir aus. Bei dieser Klasse registriert man seine Events dann.
-
Ich bin mir zwar nicht sicher, ob ich das jetzt verstanden hab, was du meintest, aber sowas ist mir jetzt gekommmen:
Ich speichere die Funktionen so:std::map< void (*)(void
, std::list< void * > > mapwobei der Schlüssel die jeweilige Funktion ist (das Parameter ist dann der this Pointer) , das mapped value ist eine Liste mit den this Pointern. Wenn ein Objekt konstruiert wird, mach ich einfach sowas wie
map[ Callback ].push_back( this );
und in der Hauptschleife ruf ich dann die Funktion mit jedem this Pointer aus der std::list auf.
(rein konzeptionell, wird natürlich etwas verpackt).
Danke für die Hilfe, manchmal braucht man einfach ein bisschen Abstand vom Problem, um die Lösung zu sehen
-
Überleg dir mal ob du da nicht mit Komposition oder zumindest reinen Interfaces besser dran bist als mit Mehrfachvererbung. Ich würde jedenfalls mal sagen dein Problem hier ist eine Folge von schlechter Abstraktion. Offenbar stellen deine Interfaces hier keine klar getrennten Konzepte dar. Ich würde eher mal da ansetzen als mit Gewalt zu versuchen ein kaputtes Design durchzusetzen.