Methode als Callback Funktion



  • Hi,

    im Rahmen einer kleinen OpenGL Anwendung habe ich mir eine Klasse OpenGLApp angelegt, die die üblichen Methoden render, update etc. enthält.

    Eine weitere Methode ist

    void GLFWCALL keyEvent(int key, int state);
    

    Ohne Klassen konnte ich diese Funktion einfach über

    glfwSetKeyCallback(keyEvent);
    

    registrieren, aber wie mache ich das denn nun mit meiner Klasse?

    Visual Studio liefert mir folgendes:

    'OpenGLApp::keyEvent': function call missing argument list; use '&OpenGLApp::keyEvent' to create a pointer to member
    

    Wenn ich es entsprechend abändere, sagt er mir jedoch:

    'glfwSetKeyCallback' : cannot convert parameter 1 from 'void (__thiscall OpenGLApp::* )(int,int)' to 'GLFWkeyfun'
    

    Ich kenne mich mit diesen c/c++ Spezialitäten leider nicht so gut aus, deswegen bitte ich um Hilfe.

    Vielen Dank im Voraus!

    Gruß,
    Tim



  • Also offensichtlich hast du ein & vergessen um einem Memberpointer zu spezifizieren. Ich bezweile aber, dass der eingeschlagene Weg so zum Erfolg führt, denn Methoden und Funktionen verhalten sich grundlegend anders in Bezug auf Callback-Mechanismen. Um eine Methode aufzurufen, braucht der Aufrufer zwingend einen Zeiger auf das Objekt, dessen Methode aufgerufen werden soll und ich weiß nicht, ob deine Bibliothek solche Aufrufmechanismen unterstützt.



  • xindon schrieb:

    ...Ohne Klassen konnte ich diese Funktion einfach über

    glfwSetKeyCallback(keyEvent);
    

    registrieren, aber wie mache ich das denn nun mit meiner Klasse?

    Garnicht. Zumindestens nicht wenn du den Typ der Callbackfunktion nicht ändern, oder eine statische Methode nutzen kannst.

    Warum? Nicht-Statische Memberfunktionen erfordern 2 Zeiger, nicht einen:
    a) ein Zeiger auf die Methode
    b) ein Zeiger auf das Objekt (Entspricht dann dem "this"-Zeiger)

    cu André



  • asc schrieb:

    Nicht-Statische Memberfunktionen erfordern 2 Zeiger, nicht einen:
    a) ein Zeiger auf die Methode
    b) ein Zeiger auf das Objekt (Entspricht dann dem "this"-Zeiger)

    Aber habe ich diese beiden Zeiger nicht? In dem Moment, in dem ich den Callback registrieren möchte, existiert die Instanz der Klasse ja schon.



  • Ja DU hast ihn, aber der Aufrufer (die glfw-Bibliothek) bräuchte ihn ja jedes Mal für den den Aufruf. Da die Bibliothek diese Form des Callbacks aber voraussichtlich nicht unterstützt, hilft Dir selber die Kenntnis des entsprechenden Zeiger nichts.
    Ein Aufruf mit einem Funktionszeiger sieht ja so aus:

    (*funcPtr)( args );
    

    wohingegen ein Methodenzeiger so verwendet wird:

    (objectPtr->*methodPtr)( args )
    

    Letzteres müsste die Bibliothek explizit unterstützen.



  • Decimad schrieb:

    Ja DU hast ihn, aber der Aufrufer (die glfw-Bibliothek) bräuchte ihn ja jedes Mal für den den Aufruf.

    Das ist genau der Punkt, den ich nicht ganz verstehe. Denn ich teile der Bibliothek ja über glfwSetKeyCallback die Adresse der Methode mit und diese ändert sich ja dann nicht mehr.

    Was ist denn genau das besondere an dieser Form des Callbacks?

    Update: Okay, ich habe gerade ein paar interessante Sachen gefunden; darunter zum Beispiel: http://www.codeproject.com/KB/cpp/Ellipses.aspx

    Ich werd mir das erst mal genauer anschauen.
    Vielen Dank für die Antworten!

    Grüße,
    Tim



  • Außerdem: Schon alleine die Typen von Funktions- und Methodenzeiger sind unterschiedlich.
    Ein Funktionszeiger hat diesen "Typ": Ret ()( args )
    Ein Methodenzeiger hat diesen "Typ": Ret (Klasse::
    ) ( args )

    Ein Methodenzeiger ist somit auf eine einzige Klasse bezogen (Ist ja auch klar, der this-Zeiger, der den Methoden unter der Haube übergeben wird muss ja passen). Um also Methoden-Callbacks auf beliebiige Klassen zu unterstützen, ist erheblich mehr Aufwand zu betreiben (siehe boost::signal in Kombination mit boost::bind oder sigc++).



  • xindon schrieb:

    Decimad schrieb:

    Ja DU hast ihn, aber der Aufrufer (die glfw-Bibliothek) bräuchte ihn ja jedes Mal für den den Aufruf.

    Das ist genau der Punkt, den ich nicht ganz verstehe. Denn ich teile der Bibliothek ja über glfwSetKeyCallback die Adresse der Methode mit und diese ändert sich ja dann nicht mehr.

    Du hast recht: Die Adresse der Methode, nicht aber des Objektes.

    Eine Methode...
    int Foo::foo(int a, int b)
    ...sieht intern eher so aus: (Sehr Vereinfacht dargestellt)
    int foo(Foo * this, int a, int b)

    Die Methode existiert nur einmal im Speicher, nicht für jedes Objekt einmal. Daher brauchst du bei Methoden 2 Angaben: a) Die Methode, b) das Objekt...

    cu André


Log in to reply