Hallo,
ich habe in C++ eine Klasse erstellt. Diese verfügt über mehrere
Methoden.
Rufe ich eine Methode der Klasse auf (von der main oder von innerhalb
der Klasse), dann verfügt diese über alle Attribute der Klasse.
Nun verwende ich innerhalb der Klasse die Bibliothek curl.
Dieser muss ich einen Pointer auf eine "Callbackfunktion" übergeben.
Sprich ich konfiguriere die Bibliothek und sobald ich die Bibliothek
ausführe werden zu bestimmten Zeitpunkten immer wieder Daten an die
Callbackfunktion gesendet.
Nun möchte ich, dass die Callbackfunktion teil meiner Klasse ist.
Also habe ich den Pointer auf die Callbackmethode wie folgt übergeben.
d.h. wenn du eine Klassenmethode da übergibst, bekommt die als this den
Parameter ptr (was auch immer der tut)
Funktionieren sollte es, wenn du einen Funktionseinzeiler als Glue-code
verwendest:
und diese Funktion an die Bibliothek übergibst
Edit:
du musst natürlich noch dafür sorgen, dass userdata dann auf dein Objekt
zeigt, wie das geht steht sicher irgendwo in der curl Dokumentation
A. R. schrieb:> Nun möchte ich, dass die Callbackfunktion teil meiner Klasse ist.> Also habe ich den Pointer auf die Callbackmethode wie folgt übergeben.> curl_easy_setopt(curl_handle_chunked, CURLOPT_WRITEFUNCTION,> &Klasse::Callbackmethode);>> Die Methode wird auch erfolgreich aufgerufen jedoch hat die> Callbackfunktionen einen anderen Pointer auf this. Kann sich das jemand> erklären?
Anders als was? Woher soll curl denn wissen, für welches Objekt die
Funktion aufgerufen werden soll?
Klaus T. schrieb:> der this pointer wird normalerweise als erster (unsichtbarer) Parameter> übergeben. Die Callback-Funktion hat aber den Prototyp> size_t function( char *ptr, size_t size, size_t nmemb, void *userdata);>> d.h. wenn du eine Klassenmethode da übergibst, bekommt die als this den> Parameter ptr (was auch immer der tut)
Eigentlich dürfte das aber gar nicht erst durch den Compiler gehen, weil
Zeiger auf Memberfunktionen und Zeiger auf normale Funktionen nicht
kompatibel sind.
> Funktionieren sollte es, wenn du einen Funktionseinzeiler als Glue-code> verwendest:> size_t glue(char *ptr, size_t size, size_t nmemb, void* userdata){> return ((*Klasse)userdata)->Callbackmethode(ptr, size, nmemb);> }
Abgesehen von der falschen Position des Sternchen sind C-Style-Casts in
C++ "pfui". So wäre es schöner:
>Anders als was? Woher soll curl denn wissen, für welches Objekt die>Funktion aufgerufen werden soll?
Ich glaube du hast recht. Bzw. ich glaube nun zu Wissen wo das
eigendlich Problem ist.
Ich erstelle eine Instanz (Objekt) einer Klasse.
Innerhalb dieser Instanz wird wird curl aufgerufen.
Die Memberfunktion, welche ich curl übergebe soll auch zu dieser Instanz
gehöhren. Also die Memberfunktion, welche curl aufruft soll Zugriff auf
alle Attribute der Instanz haben.
Die Frage müsste also sein, wie erstelle ich einen Pointer auf eine
Memberfunktion eines Objektes. Richtig?
Auf der Homepage von curl steht folgender Text:
........................
libcurl with C++
There's basically only one thing to keep in mind when using C++ instead
of C when interfacing libcurl:
The callbacks CANNOT be non-static class member functions
Example C++ code:
class AClass { static size_t write_data(void *ptr, size_t size, size_t
nmemb, void *ourpointer) { /* do what you want with the data */
} }
.......................
Ist mein Vorhaben also überhaupt möglich?
Also eigendlich ist *ptr ein Pointer auf die Daten (Text),welche die
Bibliothek empfängt. Die einzigen Daten die ich an die Callbackfunktion
übergeben kann sind Daten in void *userdata.
A. R. schrieb:> Ist mein Vorhaben also überhaupt möglich?
jein ... Ich vermute mal das Userdata ein Pointer auf ein beliebiges
Datenobjekt ist was man dem Aufruf mitgibt?
Dann kannst du eine statische dispatch Methode machen welche als
Userdata den Pointer auf die Klasse mitbekommt und auf diesem dann die
Callbackfunktion aufruft.
A. R. schrieb:> Die Frage müsste also sein, wie erstelle ich einen Pointer auf eine> Memberfunktion eines Objektes. Richtig?
Die Frage könnte man stellen, aber die Antwort lautet "gar nicht".
Einem Pointer auf eine Memberfunktion muß man immer beim Aufruf das
Objekt übergeben. Der Pointer enthält nicht selbst noch die Adresse des
Objekts sondern nur die der Memberfunktion. Daher geht das also nicht
so, wie du es dir vorstellst.
> Auf der Homepage von curl steht folgender Text:>> ........................> libcurl with C++>> There's basically only one thing to keep in mind when using C++ instead> of C when interfacing libcurl:>> The callbacks CANNOT be non-static class member functions
Richtig. Streng genommen dürfen es gar keine Memberfunktionen sein, auch
keine statischen, aber die funktionieren in der Praxis üblicherweise
trotzdem.
> Ist mein Vorhaben also überhaupt möglich?> size_t function( char *ptr, size_t size, size_t nmemb, void *userdata);> Also eigendlich ist *ptr ein Pointer auf die Daten (Text),welche die> Bibliothek empfängt. Die einzigen Daten die ich an die Callbackfunktion> übergeben kann sind Daten in void *userdata.
Genau. Und da übergibst du einen Zeiger auf dein Objekt. Das Prinzip ist
wie von Klaus T. beschrieben, und das ist auch das gleiche, was Läubi
meint.
Du definierst eine nonmember-Funktion, die du als Callback-Funktion für
curl verwendest. Die bekommt als userdata einen Zeiger auf dein Objekt,
konvertiert diesen in den passenden Typ und ruft damit dann die
Memberfunktion auf. Die Syntax, die ich oben beschrieben habe, sollte so
funtkionieren.
Was oben noch vergessen wurde: Die Funktion sollte der Vollständigkeit
halber noch als extern "C" definiert sein, da sie ja von einem C-API aus
aufgerufen werden soll. Also insgesamt ungefähr sowas:
Und dann mußt du eben noch mit CURLOPT_WRITEDATA den Zeiger auf dein
Objekt an curl übergeben, damit es diesen dann nacher als userdata an
deine Funktion weitergibt.
Bei der Gelegenheit könnte man den char* und die Größe auch noch gleich
in einen std::string wandeln ;)
Gibt es eigentlich keinen fertigen C++ Wrapper für curl?
Vielen vielen Dank für die Hilfe.
Denke, dass ich alles verstanden habe. Ich habe aber noch eine Frage.
Wie bekomme ich am geschicktesten innerhalb einer Methode einen Pointer
auf das Objekt der Klasse?
Ich könnte mir eine Settermethode erstellen und somit aus der Main einen
Pointer an meine Klasse übergeben. Aber kann man auch innerhalb einer
Memberfunktion überprüfen, für welches Objekt sie aufgerufen worden ist?