Funktionzeiger in eine map
-
Ich habe folgendes Problem:
Headerfiles: File 1: typedef void (*TFunction)(); class cWebservice{ public: callFunction(); regFunction(string pFunctionName, TFunction pFunction); privat: map<string, TFunction> cMapFunction; } File2: class CAuth : public CWebservice{ public: CAuth(); setValue(); getValue() } CPP: CAuth::CAuth(){ regFunction("setValue", &CAuth::setValue); regFunction("getValue", &CAuthgetValue); }Die Funktion "callFunction" erhält einen String der den Namen der zu aufrufenden Funktion. Mit cMapFunction["setValue"] würde die dazugehörige Funktion aufgerufen. Wen ich das ganze nicht Klassenbasiert mache funktioniert es. Mit den Klassen habe ich Probleme. Der Typ TFunction ist nicht richtig.
Fehlermeldung:
error: no matching function for call to âCAuth::regFunction(const char [8], void (CAuth::)())â
CWebservice.h:36: note: candidates are: void CWebservice::regFunction(std::string, void ()())
Wie kann ich das Problem lösen? Ich möchte aber noch weitere Klassen von der Basisklasse CWebservice ableiten.Danke
-
Zeiger auf (nicht-statische) Memberfunktionen haben einen anderen Typ als Zeiger auf freie Funktionen. Schau Dir mal die FAQ dazu an:
http://www.parashift.com/c++-faq-lite/pointers-to-members.html
-
Ok
ich müsste also:
typedef void (CAuth::*TFunction)(void);
definieren???Kannst du mir nicht ein Beispiel geben?
Wie kann ich dann aber andere Klassen von dieser klasse ableiten?
-
Kann mir niemand weiterhelfen?
-
Eine einigermaßen generelle Lösung für dieses Problem zu schreiben ist gar nicht mal so schnell getan. Glücklicherweise gibt es schon fertige Lösungen, in deinem Falle beispielsweise boost::function und da du das ja als Signale anwenden möchtest boost::signals oder auch sigc++.
-
Hmm.. Leider verstehe ich jetzt nur noch Bahnhof.
Kann mir das jemand mit einfacheneren Worten erklären?

-
Du kennen http://www.boost.org ? Du wissen dann auch was boost::function sein tun.
-
Sorry für die Textwand. Das hier hatte ich mal geschrieben, als ich mich mit templates üben wollte und vor allem, als ich noch nicht von boost wusste.
Boost ist eine ausgereifte C++-Bibliothek, die viele oft nachgefragte Funktionalitäten bietet. Ein Teil davon kommt in abgeänderter Form auch im nächsten C++ zum Einsatz. Schau einfach mal unter www.boost.org rein!Zu meinem Code. Alles leitet von callback_base ab, drum speicherst du bei Dir in der Map Zeiger auf callback_bases.
Mit callback_base< int() > fasst du z.B. alle Funktions- und Methoden-Zeiger zusammen die int zurückgeben und keinen Parameter haben.
Mit make_callback_function( Funktionsname ) machst du callback_base-kompatible Objekte, die eine statische Funktion aufrufen, mit make_callback_method( this, &meineKlasse::meineFunktion ); dann entsprechendes für Methoden. Ich hab gerade nicht so viel Zeit das alles zu erklären...jemand wartet auf mich. Schau es Dir einfach an, so in etwa kann man das lösen.namespace callback { template< typename bla > class callback_base {}; template< typename bla > class callback_method : public callback_base< bla > {}; template< typename bla > class callback_function : public callback_base< bla > {}; // // 0 parameters // template< typename Ret > class callback_base<Ret()> { public: virtual Ret exec() = 0; virtual callback_base* clone() const = 0; virtual bool operator==( const callback_base< Ret() >& other ) const = 0; }; template< typename T, typename Ret > class callback_method<Ret (T::*)()> : public callback_base< Ret() > { typedef Ret (T::*Method)( ); T* objectPtr; Method methodPtr; public: callback_method( T *pObject, Method pMethod ) : objectPtr(pObject), methodPtr(pMethod) {} callback_method* clone() const { return new callback_method( objectPtr, methodPtr ); } Ret exec() { return (objectPtr->*methodPtr)() } bool operator==( const callback_base< Ret() >& other ) const { const callback_method* meth = dynamic_cast<const callback_method*>(&other); if( meth ) return (objectPtr==meth->objectPtr) && (methodPtr==meth->methodPtr); else return false; } }; template< typename Ret > class callback_function<Ret()> : public callback_base< Ret() > { typedef Ret(*func)(); func myfunc; public: callback_function( func function ) : myfunc( function ) { } callback_function* clone() const { return new callback_function( myfunc ); } Ret exec() { return (*myfunc)(); } bool operator==( const callback_base< Ret() >& other ) const { const callback_function* func = dynamic_cast<const callback_function*>(&other); if( func ) return (myfunc==func->myfunc); else return false; } }; // // 1 parameters // template< typename Ret, typename P1 > class callback_base<Ret (P1)> { public: virtual Ret exec(P1) = 0; //************ virtual callback_base* clone() const = 0; virtual bool operator==( const callback_base< Ret(P1) >& other ) const = 0; }; template< typename T, typename Ret, typename P1 > //*************** class callback_method<Ret (T::*)(P1)> : public callback_base< Ret (P1) > //*************** { typedef Ret (T::*Method)( P1 ); //***************** T* objectPtr; Method methodPtr; public: callback_method( T *pObject, Method pMethod ) : objectPtr(pObject), methodPtr(pMethod) {} callback_method* clone() const { return new callback_method( objectPtr, methodPtr ); } Ret exec(P1 p1) //********** { return (objectPtr->*methodPtr)(p1); } //********** bool operator==( const callback_base< Ret(P1) >& other ) const { const callback_method* meth = dynamic_cast<const callback_method*>(&other); if( meth ) return (objectPtr==meth->objectPtr) && (methodPtr==meth->methodPtr); else return false; } }; template< typename Ret, typename P1 > //********** class callback_function<Ret (P1)> : public callback_base< Ret (P1) > //********** { typedef Ret(*func)( P1 ); // **************** func myfunc; public: callback_function( func function ) : myfunc( function ) { } callback_function* clone() const { return new callback_function( myfunc ); } Ret exec(P1 p1) { return (*myfunc)(p1); } bool operator==( const callback_base< Ret(P1) >& other ) const { const callback_function* func = dynamic_cast<const callback_function*>(&other); if( func ) return (myfunc==func->myfunc); else return false; } }; // // 2 parameters // template< typename Ret, typename P1, typename P2 > class callback_base<Ret (P1,P2)> { public: virtual Ret exec(P1,P2) = 0; //************ virtual callback_base* clone() const = 0; virtual bool operator==( const callback_base< Ret(P1,P2) >& other ) const = 0; }; template< typename T, typename Ret, typename P1, typename P2 > //*************** class callback_method<Ret (T::*)(P1,P2)> : public callback_base< Ret (P1,P2) > //*************** { typedef Ret (T::*Method)( P1,P2 ); //***************** T* objectPtr; Method methodPtr; public: callback_method( T *pObject, Method pMethod ) : objectPtr(pObject), methodPtr(pMethod) {} callback_method* clone() const { return new callback_method( objectPtr, methodPtr ); } Ret exec(P1 p1,P2 p2) //********** { return (objectPtr->*methodPtr)(p1,p2); } //********** bool operator==( const callback_base< Ret(P1,P2) >& other ) const { const callback_method* meth = dynamic_cast<const callback_method*>(&other); if( meth ) return (objectPtr==meth->objectPtr) && (methodPtr==meth->methodPtr); else return false; } }; template< typename Ret, typename P1, typename P2 > //********** class callback_function<Ret (P1,P2)> : public callback_base< Ret (P1,P2) > //********** { typedef Ret(*func)( P1,P2 ); // **************** func myfunc; public: callback_function( func function ) : myfunc( function ) { } callback_function* clone() const { return new callback_function( myfunc ); } Ret exec(P1 p1,P2 p2) { return (*myfunc)(p1,p2); } bool operator==( const callback_base< Ret(P1,P2) >& other ) const { const callback_function* func = dynamic_cast<const callback_function*>(&other); if( func ) return (myfunc==func->myfunc); else return false; } }; // // 3 parameters // template< typename Ret, typename P1, typename P2, typename P3 > class callback_base<Ret (P1,P2,P3)> { public: virtual Ret exec(P1,P2,P3) = 0; //************ virtual callback_base* clone() const = 0; virtual bool operator==( const callback_base< Ret(P1,P2,P3) >& other ) const = 0; }; template< typename T, typename Ret, typename P1, typename P2, typename P3 > //*************** class callback_method<Ret (T::*)(P1,P2,P3)> : public callback_base< Ret (P1,P2,P3) > //*************** { typedef Ret (T::*Method)( P1,P2,P3 ); //***************** T* objectPtr; Method methodPtr; public: callback_method( T *pObject, Method pMethod ) : objectPtr(pObject), methodPtr(pMethod) {} callback_method* clone() const { return new callback_method( objectPtr, methodPtr ); } Ret exec(P1 p1,P2 p2,P3 p3) //********** { return (objectPtr->*methodPtr)(p1,p2,p3); } //********** bool operator==( const callback_base< Ret(P1, P2, P3) >& other ) const { const callback_method* meth = dynamic_cast<const callback_method*>(&other); if( meth ) return (objectPtr==meth->objectPtr) && (methodPtr==meth->methodPtr); else return false; } }; template< typename Ret, typename P1, typename P2, typename P3 > //********** class callback_function<Ret (P1,P2,P3)> : public callback_base< Ret(P1,P2,P3) > //********** { typedef Ret type(P1,P2,P3); typedef Ret(*func)( P1,P2,P3 ); // **************** func myfunc; public: callback_function( func function ) : myfunc( function ) { } callback_function* clone() const { return new callback_function( myfunc ); } Ret exec(P1 p1,P2 p2,P3 p3) { return (*myfunc)(p1,p2,p3); } bool operator==( const callback_base< Ret(P1,P2,P3) >& other ) const { const callback_function* func = dynamic_cast<const callback_function*>(&other); if( func ) return (myfunc==func->myfunc); else return false; } }; // // 4 parameters // template< typename Ret, typename P1, typename P2, typename P3, typename P4 > class callback_base<Ret (P1,P2,P3,P4)> { public: virtual Ret exec(P1,P2,P3,P4) = 0; //************ virtual callback_base* clone() const = 0; virtual bool operator==( const callback_base< Ret(P1,P2,P3,P4) >& other ) const = 0; }; template< typename T, typename Ret, typename P1, typename P2, typename P3, typename P4 > //*************** class callback_method<Ret (T::*)(P1,P2,P3,P4)> : public callback_base< Ret (P1,P2,P3,P4) > //*************** { typedef Ret (T::*Method)( P1,P2,P3,P4 ); //***************** T* objectPtr; Method methodPtr; public: callback_method( T *pObject, Method pMethod ) : objectPtr(pObject), methodPtr(pMethod) {} callback_method* clone() const { return new callback_method( objectPtr, methodPtr ); } Ret exec(P1 p1,P2 p2,P3 p3,P4 p4) //********** { return (objectPtr->*methodPtr)(p1,p2,p3,p4) } //********** bool operator==( const callback_base< Ret(P1,P2,P3,P4) >& other ) const { const callback_method* meth = dynamic_cast<const callback_method*>(&other); if( meth ) return (objectPtr==meth->objectPtr) && (methodPtr==meth->methodPtr); else return false; } }; template< typename Ret, typename P1, typename P2, typename P3, typename P4 > //********** class callback_function<Ret (P1,P2,P3,P4)> : public callback_base< Ret (P1,P2,P3,P4) > //********** { typedef Ret(*func)( P1,P2,P3,P4 ); // **************** func myfunc; public: callback_function( func function ) : myfunc( function ) { } callback_function* clone() const { return new callback_function( myfunc ); } Ret exec(P1 p1,P2 p2,P3 p3,P4 p4) { return (*myfunc)(p1,p2,p3,p4); } bool operator==( const callback_base< Ret(P1,P2,P3,P4) >& other ) const { const callback_function* func = dynamic_cast<const callback_function*>(&other); if( func ) return (myfunc==func->myfunc); else return false; } }; // // 5 parameters // template< typename Ret, typename P1, typename P2, typename P3, typename P4, typename P5 > class callback_base<Ret (P1,P2,P3,P4,P5)> { public: virtual Ret exec(P1,P2,P3,P4,P5) = 0; //************ virtual callback_base* clone() const = 0; virtual bool operator==( const callback_base< Ret(P1,P2,P3,P4,P5) >& other ) const = 0; }; template< typename T, typename Ret, typename P1, typename P2, typename P3, typename P4, typename P5 > //*************** class callback_method<Ret (T::*)(P1,P2,P3,P4,P5)> : public callback_base< Ret (P1,P2,P3,P4,P5) > //*************** { typedef Ret (T::*Method)( P1,P2,P3,P4,P5 ); //***************** T* objectPtr; Method methodPtr; public: callback_method( T *pObject, Method pMethod ) : objectPtr(pObject), methodPtr(pMethod) {} callback_method* clone() const { return new callback_method( objectPtr, methodPtr ); } Ret exec(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5) //********** { return (objectPtr->*methodPtr)(p1,p2,p3,p4,p5) } //********** bool operator==( const callback_base< Ret(P1,P2,P3,P4,P5) >& other ) const { const callback_method* meth = dynamic_cast<const callback_method*>(&other); if( meth ) return (objectPtr==meth->objectPtr) && (methodPtr==meth->methodPtr); else return false; } }; template< typename Ret, typename P1, typename P2, typename P3, typename P4, typename P5 > //********** class callback_function<Ret (P1,P2,P3,P4,P5)> : public callback_base< Ret (P1,P2,P3,P4,P5) > //********** { typedef Ret(*func)( P1,P2,P3,P4,P5 ); // **************** func myfunc; public: callback_function( func function ) : myfunc( function ) { } callback_function* clone() const { return new callback_function( myfunc ); } Ret exec(P1 p1,P2 p2,P3 p3,P4 p4,P5 p5) { return (*myfunc)(p1,p2,p3,p4,p5); } bool operator==( const callback_base< Ret(P1,P2,P3,P4,P5) >& other ) const { const callback_function* func = dynamic_cast<const callback_function*>(&other); if( func ) return (myfunc==func->myfunc); else return false; } }; /* callback_function helpers */ template< typename T > callback_function<T()> make_callback_function( T (*func)() ) { return callback_function<T()>(func); } template< typename T, typename P1 > callback_function<T(P1)> make_callback_function( T (*func)(P1) ) { return callback_function<T(P1)>(func); } template< typename T, typename P1, typename P2 > callback_function<T(P1,P2)> make_callback_function( T (*func)(P1,P2) ) { return callback_function<T(P1,P2)>(func); } template< typename T, typename P1, typename P2, typename P3 > callback_function<T(P1,P2,P3)> make_callback_function( T (*func)(P1,P2,P3) ) { return callback_function<T(P1,P2,P3)>(func); } template< typename T, typename P1, typename P2, typename P3, typename P4 > callback_function<T(P1,P2,P3,P4)> make_callback_function( T (*func)(P1,P2,P3,P4) ) { return callback_function<T(P1,P2,P3,P4)>(func); } template< typename T, typename P1, typename P2, typename P3, typename P4, typename P5 > inline callback_function<T(P1,P2,P3,P4,P5)> make_callback_function( T (*func)(P1,P2,P3,P4,P5) ) { return callback_function<T(P1,P2,P3,P4,P5)>(func); } /* callback_method helpers */ template< typename S, typename T > inline callback_method<T> make_callback_method( S* bla, T func ) { return callback_method<T>(bla,func); } } // namespace callback
-
Ich komm im Moment nicht weiter. Mein Wissen ist anscheinend (noch) nicht gross genug. Ich versuche mein Problem zu beschreiben ohne meinen Lösungsansatz mit einzubeziehen.
Problem:
Ich möchte eine Basisklasse mit einer Funktion, welche einen Stream liest. Dieser Text Stream liefert den Namen einer Funktion aus der abgeleiteten Klasse. Diese Funktion ist also in der abgeleiteten Klasse implementiert. Nun soll die Basisklasse die Funktion der abgeleiteten Klasse ausführen. Die Anzahl der Funktionen kann für jede abgeleiteten Klasse verschieden sein. Einzig die Parameter und Rückgabewerte sind identisch.Wie kann ich das Problem am einfachsten lösen?
-
Nachdem Kompiliert wurde,bzw zur Laufzeit sind die Namen der Funktionen nirgends mehr vorhanden, sie sind dann wirrer Binärcode, soweit ich weiß kannst du zur Laufzeit nicht auf die "Namen" ,so wie sie im Code stehen, zugreifen.
-
Ich weiss. Darum wollte ich ja mit map den Funktionmsnamen der Funktion zuweisen.
-
Das geht einfach nicht. Zur Laufzeit sind die Funktionsnamen verschwunden. Das einzige, was du machen kannst ist, dass jede Klasse für sich selbst ihre Funktionsnamen als String inklusive Zeiger auf die Funktion verwaltet. Dann gibt es eine virtuelle Funktion in der Basisklasse, die aufgerufen wird, damit also in deiner abgeleiteten Klasse aufgerufen wird und dort kann sie dann entsprechend verteilt werden.
Das wäre dann z.B. soclass base { public: virtual some dispatch( std::string name, some s ); }; class derived : public base { typedef callback::callback_method<some (derived::*)(some)> callback_type; typedef std::map< std::string, callback_type > map_type; derived() { my_funcs_.insert( std::make_pair( std::string("some_func"), callback::make_callback_method( this, &derived::some_func ) ) ); } some dispatch( std::string name, some s ) { map_type::iterator it = my_funcs_.find(name); if( it != my_funcs_.end() ) return it->second.exec( some ); else return some(); } some some_func( some ); private: map_type my_funcs_; };Also das kompiliert jetzt nicht, nur so als grundlegende Idee. Und natürlich den Memory Leak da... aber sollte ja klar sein^^
-
vieleicht kommt das deinen Vorstellungen näher.
#include <map> #include <string> #include <iostream> using namespace std; class Base{ public: typedef void (Base::*TFunction)(); void callFunction(string functionName){ (this->*m_MapFunction[functionName])(); } void regFunction(string functionName, TFunction pFunction){ m_MapFunction[functionName]=pFunction; }; Base(){ regFunction("setValue", &Base::setValue); regFunction("getValue", &Base::getValue); }; void setValue(){ setValueVirtual(); }; void getValue(){ getValueVirtual(); }; virtual void setValueVirtual() = 0; virtual void getValueVirtual() = 0; private: map<string, TFunction> m_MapFunction; }; class Child : public Base { void setValueVirtual(){ std::cout<<"Child::setValue\n"; }; void getValueVirtual(){ std::cout<<"Child::getValue\n"; }; }; int main() { Child child; child.callFunction("setValue"); child.callFunction("getValue"); return 0; }Gruß
-
Ja, stimmt, nimm lieber die Methode von Drehleiter
Dass du da in meinem Beispiel auch Methoden von allen anderen Klassen und statische Funktionen registrieren könntest ist für diesen Fall purer Overkill.Viele Grüße
-
Ok danke für die schnellen Antworten.
Ich werde es mal versuchen.
Grosses Kompliment: Super Forum!!!
-
Ein Problem habe ich aber: Bei der vorgeschlagenen Lösung muss ich in der Basisklasse die Anzahl Funktionen schon wissen.
Diese Anzahl sollte aber erst in der abgeleiteten Klasse definiert werden. Ich möchte die Basisklasse für mehrere abgeleiteten Klassen verwenden und die Anzahl Funktionen sollten demnach nicht fix sein.
-
Naja, mach das Pointer-zeugs in den abgeleiteten Klassen und schicke den Aufruf per virtueller Funktion dorthin. Sozusagen ein Mix aus unseren beiden Vorschlägen.
-
Jep. Meiner erster Test hat geklappt!
Danke