Callback auf eine Funktion in einer Klasse: Einfaches Beispiel
-
Hallo,
in einer Klasse soll ein Ereignis mittels einer Callback-Funktion gemeldet werden.
Es gibt ja eine Menge Artikel zu diesem Thema, und viele verschiedene Probleme, aber zu meiner eingentlich recht einfachen Sache habe ich keine Lösung gefunden.Folgendes habe ich:
class threadclass { public: void setCallback( void (*callbackFunc)(std::string) ) { callback_ptr = callbackFunc; // <- this Zeiger fehlt hier } void sendMessage(std::string msg) { sendMsgQueue.push(msg); } void startThread() { boost::thread thread1(boost::bind(&threadclass::run, this)); } private: std::queue<std::string> sendMsgQueue; // Callback für eingehende Nachrichten void (threadclass::*callback_ptr) (std::string); void run() { for (;;) { if (!sendMsgQueue.empty()) { std::cout << "Neue Nachricht in der Sende-Queue: "; std::cout << sendMsgQueue.front() << std::endl; // Nachricht verarbeiten sendMsgQueue.pop(); } // Nachricht kommt von irgendwo her, melden (this->*callback_ptr)("Test"); } } };
Den Callback möchte ich in meinem Testprogramm ersteinmal auf eine Funktion setzen, am Besten wär es natürlich, dass man diese auch auf eine Memberfunktion einer anderen Klasse setzen kann.
void MessageReceived(std::string msg) { std::cout << "Nachricht: " << msg << std::endl; } int main() { threadclass t; t.setCallback(&MessageReceived); . . .
Irgendwie muss ich meine setCallback Methode ergänzen. Ich habe etwas von casts gelesen, die aber auch nicht das wahre sein sollen.
Hat jemand einen Hinweis?Danke und Gruß
Thomas
-
Schau dir mal das Observerpattern an und die Beispiele dazu, wie man sowas elegant implementieren kann.
-
wenn du bereits boost verwendest, kannst doch noch gleich
boost::function mit ins boot holen, und übersichtlichkeit gleich dazu.
-
Kolumbusplatz schrieb:
Schau dir mal das Observerpattern an und die Beispiele dazu, wie man sowas elegant implementieren kann.
Ja, das sieht gut aus. Vor allem falls doch einmal ein zweiter Empfänger hinzukommen sollte muss man nichts mehr ändern.
hey schrieb:
wenn du bereits boost verwendest, kannst doch noch gleich
boost::function mit ins boot holen, und übersichtlichkeit gleich dazu.Eigentlich habe ich boost bis jetzt nur genommen, um mir das Thread-Gefrickel zu ersparen.
Falls ich aber komplett auf Boost setzen sollte, wäre dann boost::signals das passende hierfür? Die Beispielcodes in der boost-doc sind finde ich etwas unverständlich.Aber den Code oben würde ich schon gerne noch lauffähig bekommen.
-
Im Forum hier bin ich auf folgendes gestoßen:
http://www.c-plusplus.net/forum/viewtopic-var-p-is-856627.html#856627
Kann ich das für meine Zwecke verwenden, bzw. anpassen?
Mir ist auch nicht ganz klar, wie diese Klasse dort letzendlich zu verwenden wäre.
-
Thomas_123 schrieb:
Falls ich aber komplett auf Boost setzen sollte, wäre dann boost::signals das passende hierfür? Die Beispielcodes in der boost-doc sind finde ich etwas unverständlich.
Hallo Thomas,
boost.function ist Dein Freund und DIE Callback-Funktion.
Thomas_123 schrieb:
Aber den Code oben würde ich schon gerne noch lauffähig bekommen.
Kein Problem - ändere die Zeile 23 in
// Callback für eingehende Nachrichten boost::function1< void, std::string > callback_ptr;
und die Zeile 4 nach
void setCallback( const boost::function1< void, std::string >& callbackFunc ) { callback_ptr = callbackFunc; // <- this Zeiger fehlt hier }
und natürlich den Aufruf in Zeile 36
// Nachricht kommt von irgendwo her, melden callback_ptr( "Test" );
das ganze macht ein
#include <boost/function.hpp>
erforderlich.
Der Aufruf im main() kann so bleiben. Der Funktionspointer '&MessageReceived' wird in die boost::function1 konvertiert.
Das kann man dann auch in Kombination mit boost.bind benutzen. Zum Beispiel
#include <boost/bind.hpp> class A { public: void machWas( const std::string& txt ); // ... }; int main() { threadclass t; A a; t.setCallback( boost::bind( &A::machWas, &a, _1 ) );
(nicht überprüft, ob es compiliert, hoffe es passt)
Gruß
Werner