Callback-Funktion



  • Hallo Forum,

    ich habe zwei Klassen A und B und möchte eine Callback-Funktion von Klasse B zu Klasse A (Rückgabe: void, Eingabe-Parameter: int) setzen.

    In Klasse B deklariere ich:

    - einen Funktions-Pointer:
    void (*Callback)(int)

    - die Funktion zum Setzen der Callback-Funktion:
    public:
    void setzeCallbackFunktion(void (*InFunktion)(int))

    und definiere diese Funktion zu:
    void B::setzeCallbackFunktion(void (*InFunktion)(int))
    {
    this->Callback = InFunktion;
    }

    In Klasse A rufe ich die Funktion B.setzeCallback-Funktion auf:
    B.setzeCallbackFunktion(IntegerFunktion)

    wobei void IntegerFunktion(int) deklariert ist.

    Beim Aufruf von B.setzeCallbackFunktion erhalte ich zwei Fehlermeldungen:
    -Cannot convert void(* (_closure) (int))(int) to void()(int)
    -Type mismatch in parameter 'IntegerFunktion' in call to 'B::setzeCallbackFunktion(void (
    )(int))'

    Aber ich kann doch beim Aufrufen von B.setzeCallbackFunktion der "Parameter"-Funktion IntegerFunktion weder ein "int" (Syntaxfehler) noch einen Integerwert a (IntegerFunktion(a) wird zu void ausgewertet) mitgeben. Aber was muss ich denn dann anders machen? Danke für Antworten.



  • der klassenname gehoert zum typ des zeigers:

    class A
    {
    typedef void (B::*fkt_b)( int );
    
    void setzeCallback( fkt_b f )
    {
      this->callback = f;
    }
    
    void rufeauf( B* b )
    {
       int i = 123;
       (b->*callback)( i );
    }
    
    private:
      fkt_b callback;
    
    };
    


  • Welchen Klassennamen und welchen Zeiger meinst Du? "fkt_b f" statt nur "f" in "void setzeCallback( fkt_b f )"? An dieser Stelle habe ich jedoch eine Funktion der Klasse A, dagegen gehört die Funktion setzeCallback bei mir zur Klasse B.



  • ich hab die klassennamen vertauscht...

    class B;
    
    class A
    {
      public:
        void irgendeineFunktion()
        {
          einB.setzeCallback( dieCallbackFunktion );
        }
    
        void dieCallbackFunktion( int i )
        {
          //...
        }
    
      private:
        B einB;
    };
    
    class B 
    {
    // fkt_a ist ein neuer name fuer eine funktion der klasse A,
    // die void als return wert hat und als parameter ein int erwartet
    typedef void (A::*fkt_a)( int ); 
    
    void setzeCallback( fkt_a f ) 
    { 
      this->callback = f; 
    } 
    
    void rufeauf( A* a ) 
    { 
       int i = 123; 
       (a->*callback)( i ); 
    } 
    
    private: 
      fkt_a callback; 
    
    };
    


  • In der Anleitung zum Setzen von Callback-Funktionen, nach der ich den Text geschrieben habe, steht übrigens B.setzeCallbackFunktion(*IntegerFunktion) (also IntegerFunktion dereferenziert). Der Compiler verlangt dann jedoch, dass ich IntegerFunktion als Funktion, also mit Parameterliste aufrufe. Verwende ich eine leere Parameterliste, werden mehr Parameter verlangt, schreibe ich int oder einen Integerwert a in die Parameterliste erhalte ich auch hier wieder einen Syntaxfehler oder eine Auswertung von IntegerFunktion(a).



  • @ entelechie:

    IMHO sieht das bei mir genauso aus, mit dem einen Unterschied, dass ich "dieCallbackFunktion" nicht als Funktion der Klasse A, sondern als Funktionspointer der Klasse B habe. Verwende ich keinen Funktionspointer sondern eine Funktion kann ich ihr nichts zuweisen. Und in Klasse B sollte dieCallbackFunktion bei mir schon sein.

    Hier der tatsächliche Quelltext (mit den bbCode-Tags komme ich leider nicht zurecht):

    Klasse B, Header:
    class B
    {
    public:
    void CallbackFunktion(int);
    void SetzeCallbackFunktion(void (*InFunktion)(int));
    };

    Klasse B, Quelltext:
    void B::SetzeCallbackFunktion(void (*InFunktion)(int))
    {
    this->CallbackFunktion = InFunktion;
    }

    Klasse A, Header:
    class A
    {
    public:
    void AufrufSetzeCallback();
    void MyIntegerFunktion(int InInt);

    B MyB;
    };

    Klasse A, Quelltext:
    void A::MyIntegerFunktion(int InInt)
    {
    }

    void A::AufrufSetzeCallback()
    {
    MyB.SetzeCallbackFunktion(MyIntegerFunktion);
    }



  • Korrektur:

    "void (*CallbackFunktion)(int)" statt "void CallbackFunktion(int)" bei Klasse B, Header.



  • ok, noch ein versuch 🙂
    (ich hoffe ich hab dich jetzt richtig verstanden...)

    class A;
    
    class B
    {
    	public:
    		typedef void (A::*fkt_a)( int );
    
    		void SetzeCallbackFunktion( fkt_a f );
    
    	private:
    		fkt_a callbackFunktion;
    };
    
    void B::SetzeCallbackFunktion( fkt_a f )
    {
    	this->callbackFunktion = f;
    }
    
    class A
    {
    	public:
    		void AufrufSetzeCallback();
    		void MyIntegerFunktion( int InInt );
    
    		B MyB;
    };
    
    void A::MyIntegerFunktion( int InInt )
    {
    }
    
    void A::AufrufSetzeCallback()
    {
    	MyB.SetzeCallbackFunktion( &A::MyIntegerFunktion );
    }
    


  • Ja, jetzt hast Du mich richtig verstanden. Und wenn ich Dich und Deinen Quelltext richtig verstanden habe, weiß ich jetzt auch, wo mein Fehler liegt. Aber bei Deiner Lösung kann ich als Callback-Funktion nur Member-Funktionen von A einsetzen, oder? (Das würde mir für den Augenblick auch schon reichen.)



  • Wenn du allerdings in B nicht nur Memberfunktionen von A verwenden willst (dazu bräuchtest du dann auch immer ein Objekt zum Ausführen), bleibt dir noch die Wahl:
    Mach MyIntegerfunktion global, oder packe sie in einen Namensbereich, dann hat sie die gewünschte Signatur void (*)(int)
    Mach sie static. Dann hat sie ebenfalls die gewünschte Form:

    Klasse B, Header:
    class B
    {
    public:
    void CallbackFunktion(int);
    void SetzeCallbackFunktion(void (*InFunktion)(int));
    };
    
    Klasse B, Quelltext:
    void B::SetzeCallbackFunktion(void (*InFunktion)(int))
    {
    this->CallbackFunktion = InFunktion;
    }
    
    Klasse A, Header:
    class A
    {
    public:
    void AufrufSetzeCallback();
    static void MyIntegerFunktion(int InInt); //static gemacht
    
    B MyB;
    };
    
    Klasse A, Quelltext:
    void A::MyIntegerFunktion(int InInt)
    {
    }
    
    void A::AufrufSetzeCallback()
    {
    MyB.SetzeCallbackFunktion(MyIntegerFunktion);
    }
    


  • Ihr wisst aber schon, daß man in C++ Callbacks eigentlich anders implementiert???

    Den vorgestellten Weg wählt man eigentlich nur (noch), wenn eine C-API dies in einer solchen Form fordert.



  • drei Fragezeichen???
    der OP wollte doch einen Funktionszeiger?!



  • Marc++us schrieb:

    Ihr wisst aber schon, daß man in C++ Callbacks eigentlich anders implementiert???

    und wie macht man das??



  • überschreiben virtuelle methoden.



  • Davies Vorschlag ist angenommen, die Methode wird jetzt static. Vielen Dank auch an alle anderen.



  • Die Methode ist jetzt doch nicht static, da sie von mehreren Instanzen der Klasse verwendet werden soll. Mein Programm folgt jetzt entelechies Vorschlag von 16:29:18 12.08.2003, also dem Vorschlag, die Callback-Funktion mit einem A:: davor zu deklarieren.

    Aber wie rufe ich dann schlussendlich die Callback-Funktion B.callbackFunktion auf? Schreibe ich B.callbackFunktion, erhalte ich die Meldung, B.callbackFunktion sei keine Funktion.



  • dann macht man es so:

    class Test
    {
    private:
      int value;
    
      void callbackImpl()
      {
        cout<<value;
      }
    public:
      Test(int value) : value(value) {}
    
      static void callback(Test* self)
      {
        self->callbackImpl();
      }
    };
    

    der this-Zeiger muss ja irgendwo herkommen.

    denn vergiss nicht:

    von der logik her ist
    f.foo() == foo(&f)



  • Du hast void callbackImpl(), ich habe void A::callbackImpl().

    Und meinst Du mit self this?


Anmelden zum Antworten