Funktionspointer zu Memberfunktion beliebiger Klasse
-
Hallo,
ich komme gleich zur Sache:
Ich bastle mir zur Zeit eine Art Framework besierend auf der SDL um damit später diverse Spiele zu entwickeln, ich habe da so einige Ideen.
Auf jeden Fall arbeite ich im Moment an einer Art Eventsystem, das in etwa so aussieht:
Jede Klasse, die irgendwie Events behandeln soll, baut auf eine Basisklasse auf, die im Prinzip nichts anderes macht als sicherzustellen dass der Eventhandler der erbenden Klasse aufgerufen wird, dazu muss im Konstruktor der Klasse allerdings der Aufruf
((MGDK_App *) MGDK_Setup::app )->RegisterEvent(this);
erfolgen. Dieser registriert (offensichtlich..) die Klasse als Eventklasse und führt dann, immer wenn es ein Event zu behandeln gibt, die virtuelle Funktion HandleEvents(SDL_Event *, bool aus. 1. Argument enthält alle relevanten Informationen zum Event, der Pointer auf den Boolean wird zum Beenden nach der Ausführung des EventLoops benutzt (*quit = true würde nach dem durchlauf aller Eventhandler das Programm beenden, sofern der EventLoop das letzte Element im Programm ist.)
Naja, jetzt zum eigentlichen Problem.
Ich habe eine Klasse entworfen, die später einen Button auf dem Bildschirm darstellt und natürlich auch die Events von diesem Behandelt.
Die HandleEvents-Funktion sieht zur Zeit so aus:
void MGDK_GuiButton::HandleEvents(SDL_Event *evnt, bool *quit){ switch ( evnt->type ){ case SDL_MOUSEBUTTONDOWN: if ( this->mbdown != NULL )this->mbdown(evnt, quit); } }
Die Funktion ruft im Grunde nur den Funktionspointer mbdown mit der Eventstruktur und dem Terminierungsboolean (klasse Name, ich weiß :>)(void (*mbdown) (SDL_Event *, bool *);) auf, sofern der nicht NULL ist.
Hier kommts zum Problem. Man könnte da jetzt jede erdenkliche Nicht-Member-Funktion einsetzten, allerdings möchte ich die ganze Sache etwas nach dem Signal-Slot-Konzept vom Qt richten, d.h., man kann mittels einer Funktion ein Signal("Aktion") mit einem Slot("Reaktion") verbinden. In dem Fall hier wäre die Aktion dann das Klicken auf den Button, die Reaktion das Aufrufen des Voidpointers.
Das stellt soweit kein Problem dar, solange ich, wie oben beschrieben, Nicht-Member-Funktion einsetze. Ich würde es aber gerne wie folgt konzipieren:
class Slot{ public: void mbdown(SDL_Event *, bool *); }; void Slot::mbdown( SDL_Event *evnt, bool *quit ){ //irgendwelche Daten verändern etc. } class Signal : public MGDK_EventObject{ public: Signal(); void HandleEvents(SDL_Event *, bool *); void (*mbdown)(SDL_Event *, bool *); }; Signal::Signal(){ ((MGDK_App *) MGDK_Setup::app )->RegisterEvent(this); } void Signal::HandleEvents(SDL_Event *evnt, bool *quit){ switch ( evnt->type ){ case SDL_MOUSEBUTTONDOWN: this->mbdown(evnt, quit); } } // ---- Signal sig; Slot slot; sig.mbdown = slot.mbdown;
So stelle ich mir das vor. In Wirklichkeit geht das allerdings nicht, da ich keine Funktionspointer auf Memberfunktionen beliebiger Klassen machen kann.
Solange ich nur die Slot-Klasse behandeln wollte, würde das natürlich kein Problem darstellen, ich müsste ja einfach nur einen Memberpointer für Slot machen. Allerdings, wie gesagt, sollte das dynamisch funktionieren. Hat jemand eine Idee wie das geht?
lg.
PS: MGDK_EventObject ist die Basisklasse für Eventorientierte Klassen.
// Ist seltsamerweise im C++/CLI mit .NET gelandet, wäre nett wenn das jemand in die C++ Rubrik verschieben könnte.
-
Keine Lust, das durchzulesen, aber es gibt z.B. boost::signals. Oder wenn du es low level magst, boost::function
-
Hi,
danke für den Tipp, ich wollte allerdings kein boost nutzen, konnte aus einem unerfindlichen Grund boost noch nie gut leiden
Allerdings haben mich die boost::signal Beispiele auf die Idee gebracht, das ganze mit dem ()-Operator zu machen. Ich bin mir nicht sicher, wie ich das bei mehreren Event-Typen regeln soll, da fällt mir aber sicher noch was ein.
Gruß
immapoint~Edit: Habs nun mit Templates hinbekommen, das Signal nimmt einmal ein Objekt vom Typ T und einen Memberpointer vom Typ T:: an. Hätte ich früher drauf kommen können