/** * \file callback.h * * \brief Implementiert callbacks aus Membern und Funktionen. * * Enthält alle nötigen Klassen, um sowohl aus Klassenmembern * als auch aus normalen Funktionen Callbacks zu machen. Das heißt * das sowohl die Adresse des Objekts als auch die der Methode/Funktion * gespeichert wird und bei bedarf richtig aufgerufen wird. Es lassen sich * also Methoden in Arrays oder Listen vorhalten. * * \author Georg Steffers * * \date 04.12.2003 * * \version ..2001 (Georg Steffers): erste implementation * \version 2001-2003 (Georg Steffers): diverse Modifikationen * \version 04.12.2003 (Georg Steffers): beginn der Dokumentation via doxygen */ /* * Copyright (C)2003 Georg Steffers * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ using namespace std; #include // enthaelt die adressen unserer callbackfunktion bzw. der Klasse und des // Members die wir aufrufen moechten....(dies hier ist die Basisklasse // diese wird gleich spezifiziert class FunctorBase { public: // dient wohl nur dazu die groesse eines Member-Pointers zu bestimmen. typedef void (FunctorBase::*t_MemberFunc)(); // hierdrin wird der Quatsch gespeichert.... union { const void* Callback; char CallbackMember[sizeof(t_MemberFunc)]; }; void* Class; // Konstruktoren // wichtig, wenn ein Object der Klasse FunctorBase oder einer // abgeleiteten Klasse kopiert werden soll. FunctorBase() : Class(0), Callback(0) {} // Hiermit wird eine FunctorBase angelegt. FunctorBase(const void* _Class, const void* _Callback, size_t Size) { if(_Class) { //Mit nem Member initialisiert Class=(void*)_Class; memcpy(CallbackMember, _Callback, Size); } else { // Mit ner normalen Funktion initialisiert Class=NULL; Callback=_Callback; } } }; // dies wird nu ein Functor, der einen Callback aufnehmen kann, der einen // beliebiegen Parameter hat und void zurueckgibt. template class callback : protected FunctorBase { // wir machen einen protected Konstruktor fuer die Klasse, damit nur // abgeleitete Klassen einen callback erzeugen koennen. Diese mussen dann // sicherstellen, das Funktor1 nur mit Methoden oder Funktionen erzeugt // wird, die genau einen Parameter akzeptieren und void zurueckliefern. // Der Teil RestoreTypeAndCall(_RTAC) initialisiert RestoreTypeAndCall // auf _RTAC. protected: typedef void (*t_RestoreTypeAndCall)(const FunctorBase&, P1, P2); callback(t_RestoreTypeAndCall _RTAC, const void *_Class, const void *_Callback, size_t _Size) : FunctorBase (_Class, _Callback, _Size), RestoreTypeAndCall(_RTAC) {} private: t_RestoreTypeAndCall RestoreTypeAndCall; public: callback() {} void operator() (P1 p1, P2 p2) const { // ueber den koennen wir nachher // den Callback aufrufen. if(Class) // Wir haben nen Member... RestoreTypeAndCall(*this, p1, p2); else // normale Funktion, koennen wir direkt aufrufen... ((void (*)(P1,P2))Callback)(p1, p2); } const void* getcb(void) { return Callback; } int is_null(void) { if(Class != 0 || Callback != 0) return false; return true; } }; // beim speichern der Klasse als void* ist uns der Typ der Klasse und // auch das eigentliche Object verloren gegangen. // Deshalb kommt hier jetzt ne Klasse, die den Typ kennt und // bei bedarf (jedesmal wenn eine Memberfunktion als Callback aufgerufen // werden soll) zurueckwandelt. // Ein template: Callee ist jede beliebige Klasse und Func jeder Member template class MemberTranslator : public callback { public: MemberTranslator(Callee &Class, const Func &MemberFunction) : callback(RestoreTypeAndCall, &Class, &MemberFunction, sizeof(Func)) {} static void RestoreTypeAndCall(const FunctorBase &ftor, P1 p1, P2 p2) { Callee* Who = (Callee*)(ftor.Class); Func TheMemberFunction=*(Func*)(void*)(ftor.CallbackMember); (Who->*TheMemberFunction)(p1, p2); } }; // Da der Konstruktor von callback protected ist brauchen wir noch einen // Translator um aus normalen Funktionen Callbacks zu machen. template class FunctionTranslator : public callback { public: FunctionTranslator(void *regularFunc) : callback(NULL,NULL,regularFunc,0) {} }; // und jetzt noch 2 makeCallback Templates um das erstellen von Callbacks zu // erleichtern. template callback mk_callback(Callee &Class, void (Callee::*Member)(P1, P2)) { return MemberTranslator(Class, Member); } template callback mk_callback(void (*theFunc)(P1, P2)) { return FunctionTranslator((void*)theFunc); }