Callback Funktionen und deren Aufrufe
-
Hallo Zusammen,
Ich habe eine Frage im Bezug auf Callback Funktionen:
Ich habe 2 Klassen wovon eine, unter bestimmten Bedingung, die FUnktion der
zweiten Klassen aufruft(callback). Dazu habe ich auch eine main.cpp zur Erzeugung
aller Instanzen.// Erste Klasse, nachdem eine bestimmte Bedingung bei dem Aufruf // von listen_port dieser Klasse eingetreten ist, wird die callback executiert. void Worker::listen_port(unsigned short upper_bound, void* nm, void (NonsenseManager::*meth_ptr)(void* ptr2obj, unsigned int index) ){ std::srand(time(NULL)) ; unsigned short i = upper_bound ; unsigned int number ; for( ; i >=0 ; i--) if(i > 1) while ( (number = std::rand() %i) == 0 ) ( ((NonsenseManager *)nm)->*meth_ptr)((void *)nm, i) ; // callback else ( ((NonsenseManager *)nm)->*meth_ptr)((void *)nm, i) ; // callback ; } //........ // Zweite Klasse deren Funktion als "callback" aufgerufen wird. void NonsenseManager::func_quad(unsigned int index){ values_container[index] = index * index ; } // statische callback function, forwards query to another method void NonsenseManager::wrapper_func(void* ptr2obj, unsigned int index){ NonsenseManager* active = (NonsenseManager *) ptr2obj ; cout << __FUNCTION__ << ":callback has been called for index:" << index << endl; active->func_quad(index) ; }Bis jetzt klappt alles gut, wenn ich aber durch einen main.cpp die
Worker->listen_port() aufrufen moechte:// von main.cpp int main(void) { unsigned short upper = 20 ; NonsenseManager* nm = new NonsenseManager(upper) ; cout << __FUNCTION__ << ": nonsense manager created" << endl; unsigned int i =0 ; Worker* workoholic = new Worker() ; workoholic->listen_port(upper, (void *) nm, &NonsenseManager::wrapper_func); // hier meckert der compiler cout << __FUNCTION__ << ": hold tight, workoholic on air" << endl; return 0; }kriege ich einen Fehlermeldung wie:
main.cpp:18: error: no matching function for call to ‘Worker::listen_port(short unsigned int&, void*, void ()(void, unsigned int))’
Worker.h:19: note: candidates are: void Worker::listen_port(short unsigned int, void*, void (NonsenseManager::)(void, unsigned int))Wieso klappt der Aufruf von
workoholic->listen_port(upper, (void *) nm, &NonsenseManager::wrapper_func);nicht? Ich sehe den Fehler nicht, weil, sowie es bei den Beispielen gezeigt wird,
muesste so klappen..(Ich habe bei meiner ersten callback implementation im Netz
vorhandenen Beispiele gefolgt. )
http://www.c-plusplus.net/forum/viewtopic-var-t-is-126801-and-highlight-is-callback.html
http://www.newty.de/fpt/callback.html#chapter3Danke im voraus,
-
Wie sieht den der Header aus? Also die Deklarationen?
Im übrigen würde ich dir empfehlen das über Templates zu lösen. Dann kannst du das mit dem void* casten auch gerade weglassen.
btw.
Da fehlen auch noch deletes.
-
Hallo drakon,
drakon schrieb:
Wie sieht den der Header aus? Also die Deklarationen?
die header dateien sehen so aus:
// von Worker.h class Worker { public: Worker() ; virtual ~Worker() ; void listen_port(unsigned short upper_bound, void* nm, void (NonsenseManager::*meth_ptr)(void* ptr2obj, unsigned int index)); }; // von NonsenseManager.h class NonsenseManager { public: NonsenseManager(unsigned short no) ; virtual ~NonsenseManager() ; static void wrapper_func(void* ptr2obj, unsigned int index) ; //callback signatur void func_quad(unsigned int index) ; void dumpNonsense(); private: unsigned int* values_container ; unsigned short upper_bound ; };Im übrigen würde ich dir empfehlen das über Templates zu lösen. Dann kannst du das mit dem void* casten auch gerade weglassen.
ok, danke fuer die Empfehlung. Es geht gerade fuer mich darum, dass ich
mal nachvollziehe wie callback Funktionen bei c++ implementiert werden.
Deswegen dieser Weg...btw.
Da fehlen auch noch deletes.
haste recht, bin gerade dabei...Gruss,
-
Der Fehler lag daran, dass eine statische member function keine this pointer
annehmen darf. Solche statische Funktionen sind direkt addressierbar. Da der
callback-funktion so deklariert ist:static void wrapper_func(void* ptr2obj, unsigned int index) ; //callback signaturist die richtige version von listen_port:
void Worker::listen_port(unsigned short upper_bound, void* nm, void (*meth_ptr)(void* ptr2obj, unsigned int index) ){ std::srand(time(NULL)) ; unsigned short i = upper_bound ; unsigned int number ; for( ; i >=0 ; i--) if(i > 1) while ( (number = std::rand() %i) == 0 ) (*meth_ptr)((void *)nm, i) ; // callback else (*meth_ptr)((void *)nm, i) ; // callback ; }Gruss,
-
Ich würde das mit Interface-Klassen lösen. Je nach komplexität bzw. gewünschter Flexibilität, wären Templates hier vielleicht etwas übertrieben.
Irgendwie so z.B.:
#include <iostream> #include <vector> //Interface class ICallbackInterface { public: virtual int someCallback(int param1, int param2) = 0; }; //callback handler: verwaltet callbacks und führt sie aus class CCallbackHandler { public: //registriert callbacks void addCallback(ICallbackInterface& callback) { myCallbacks.push_back(&callback); } //ruft alle registrierten callbacks auf void executeCallbacks() { for(std::vector<ICallbackInterface*>::iterator iter = myCallbacks.begin(); iter != myCallbacks.end(); ++iter) { std::cout << (*iter)->someCallback(1, 3) << '\n'; } } private: //speichert die registrierten callbacks std::vector<ICallbackInterface*> myCallbacks; }; //bindet das interface ein und kann daher beim handler registriert werden class CCallbackUser1 : public ICallbackInterface { public: virtual int someCallback(int param1, int param2) { return param1 + param2; } }; //bindet das interface ein und kann daher beim handler registriert werden class CCallbackUser2 : public ICallbackInterface { public: virtual int someCallback(int param1, int param2) { return param1 * param2; } }; int main( ) { //callbacks CCallbackUser1 cbu1; CCallbackUser2 cbu2; //handler CCallbackHandler handler; //callbacks registrieren... handler.addCallback(cbu1); handler.addCallback(cbu2); //...und ausfuehren handler.executeCallbacks(); return 0; }
-
jsbach schrieb:
...
Wobei sich natürlich die Frage stellt, warum das static, bzw. IN der Klasse ist. Da könntest du natürlich die Funktion aus der Klasse nehmen, da sie ja nix davon nix wissen muss/kann/darf.
Tachyon schrieb:
Ich würde das mit Interface-Klassen lösen. Je nach komplexität bzw. gewünschter Flexibilität, wären Templates hier vielleicht etwas übertrieben.
In seinem Fall wäre das wahrscheinlich eleganter. Jedoch wollte er Methoden Pointer verstehen. Da hilft es ihm nix, wenn er dann ein Interface draus macht.

Wenn ich Templates in Verbindug mit Methoden Pointer einsetze, dann wissen die meis überhaupt nix über die andere Klasse.