C++ member Methode als Callback-Funktion übergeben



  • Hallo zusammen,

    ich versuche eine Klasse zuschreiben in der sich eine Callback Funktion
    befindet. Ich möchte sie als nicht-statischen deklariert,weil ich in der
    Callback-Funktion die anderen member Funktion und die andern Membern
    Werte zugreifen möchte. meine Frage Ob es möglich ist, denn die meisten
    beispiele und mein Programm kriege ich zum laufen nur wenn die
    Callbackfunktion als globale Funktion definiere oder als statische
    Funktion.

    Hier ist mein Code:

    myclass.hpp

    //void * callBackFunction(void *arg) ; //callback als globale Funktion
    class myClass
    {
    
      public:
        myClass();
        void                              flaeche();
        void                              creatTreads();
        void*                             callBackFunction(void *arg);
        //static void*  callBackFunction(void *arg);
        vtkSmartPointer                   <vtkMultiThreader> threads;
      private:
           double  breite ;
           double  laenge;
     };
    

    myclass.cpp

    myClass::myClass(){
    
       this->laenge = 0.0;
       this->breite = 0.0;
    
    }
    
    void* myClass::callBackFunction(void *arg ){
    
        // explicitly cast to a pointer
        int id          = *((int *)arg);        // process ID
        myClass *mySelf = (myClass*) arg;
        mySelf->flaeche();
    
       std::cout<<"thread Function: process :prozess.id="<<id<<std::endl;
    }
    void myClass::flaeche(){
    
      double sr =this->laenge * this->breite;
     cout<<"flaeche():sr ="<<sr<< "lange="<<this->laenge<<"breite ="<<this->breit<<endl;
    
    }
    
    void myClass::creatTreads(){
    
       this->laenge =10.5;
       this->breite = 10.5;
    
      threads = vtkSmartPointer<vtkMultiThreader>::New();
       cout << "Initialization DONE" << endl;
       int thID = 0;
       thID = threads->SpawnThread((vtkThreadFunctionType)(*callBackFunction), &thID);
    
    }
    int main(int argc, char *argv[]) {
    
         myClass C;
         C.creatTreads();
    

    Allerdings erhalte ich dann einen Fehler:

    :104:57: error: invalid use of member function (did you forget the ‘()’ ?)
    

    Wie könnte man diese Problem umgehen? Die CallBackfunktion als static
    deklarieren aber wie kann man auf den aktullen Object zugreifen oder
    gibts auch andere Lösungen?

    Danke schön mal im Voraus
    Sokratss



  • Wenn du Memberfunktionen binden willst, brauchst du Memberfunktionszeiger. Das Standardnachschlagewerk, wenns um alle möglichen Varianten von Funktionszeigern geht:
    http://www.newty.de/fpt/index.html

    In C++ kannst du allerdings die viel mächtigere Klasse std::function nehmen, an die du mit std::bind() und Lambda-Ausdrücken so gut wie alles binden kannst. Schau dazu vielleicht auf www.cppreference.com nach.


  • Mod

    Die Frage ist wie immer: Memberfunktion von welchem Objekt? Deine Erklärung, dass es auch eine Option wäre, die gleiche Funktion static oder global zu machen ist da sehr verwirrend, denn diese Funktionen wären schließlich auch ohne ein Objekt der Klasse aufrufbar.

    Jedenfalls muss dein Caller wissen, auf welchem Objekt er die Memberfunktion aufrufen soll. Falls dein Caller das nicht weiß, sondern bloß ein allgemeines, aufrufbares Objekt erwartet, dann kannst du auch das gewünschte Objekt und die gewünschte Memberfunktion zu einem Paket zusammenschnüren und übergeben. Die Standardbibliothek kennt das ab C++11 fix und fertig als std::bind. Vor C++11 gibt's da auch Methoden für (Header functional ), ist aber ziemlich unschön zu bedienen, so dass man ohne C++11 wohl besser mal boost::bind angucken sollte.

    Ein Beispiel (zusammengefügt von en.cppreference.com):

    #include <iostream>
    #include <functional>
    
    struct Foo {
        void print_sum(int n1, int n2)
        {
            std::cout << n1+n2 << '\n';
        }
        int data = 10;
    };
    
    int main()
    {
        using namespace std::placeholders; //for _1, _2, _3...
    
        // bind to a member function
        Foo foo;
        auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1);
        f3(5);
    }
    

    http://ideone.com/BUpD4t



  • [quote="SeppJ"]Die Frage ist wie immer: Memberfunktion von welchem Objekt?
    ich möchte auf das gleiche Object zugreiffen, ich habe das programm ein beischen geändert, nun habe ich cid Callbackfuntion doch als static Methode deklariert und wolte die aktuelle Object als Parmeter für sie übergeben

    class myClass
    {
    
      public:
    
        myClass();
        void          flaeche();
        vtkSmartPointer<vtkMultiThreader> threads;
    
        void          creatTreads();
        static void  callBackFunction(myClass *arg); 
    
        private:
           double  breite ;
           double  laenge;
        };
    
    myClass::myClass(){
    
       this->laenge = 0.0;
       this->breite = 0.0;
    
    }
    
    void myClass::callBackFunction(myClass *arg ){ 
    
        myClass *mySelf = (myClass*) arg;
    
        mySelf->flaeche();
    
        boost::bind(&myClass::flaeche, &mySelf);
    
    }
    void myClass::flaeche(){
    
      double sr =this->laenge * this->breite;
    
      cout<<"flaeche():sr ="<<sr<< "lange="<<this->laenge<<"breite ="<<this->breite<<endl;
    
    }
    
    void myClass::creatTreads(){
    
       this->laenge =10.5;
       this->breite = 10.5;
    
       vtkSmartPointer<vtkMultiThreader> threads = vtkSmartPointer<vtkMultiThreader>::New();
    
       int thID = 0;
    
       thID = threads->SpawnThread((vtkThreadFunctionType)(callBackFunction)(this), &thID);
    
    }
    

    aber da schmeiß mir die Complier folgende fehler:

    : error: void value not ignored as it ought to be
    


  • Hallo,

    laut SpawnThread kannst du als 2. Parameter ein beliebiges Objekt übergeben (d.h. this als Zeiger auf deine Klasse):

    thID = threads->SpawnThread((vtkThreadFunctionType)callBackFunction, this);
    

    (dein bisheriges Konstrukt ergab überhaupt keinen Sinn...)



  • Hallo,
    das habe ich schön probiert aber wie kann ich auf das Object in callbackfunktion
    zugreiffen wenn es nicht als parmeter für sie übergeben wird.

    Th69 schrieb:

    thID = threads->SpawnThread((vtkThreadFunctionType)callBackFunction, this);
    

    (dein bisheriges Konstrukt ergab überhaupt keinen Sinn...)



  • Ändere mal deine Callback-Funktion zu

    void myClass::callBackFunction(void *arg) // <- Parametertyp ändern 
    {
      myClass *mySelf = (myClass*) arg;
    
      // ...
    }
    


  • Th69 schrieb:

    Ändere mal deine Callback-Funktion zu

    void myClass::callBackFunction(void *arg) // <- Parametertyp ändern 
    {
      myClass *mySelf = (myClass*) arg;
      
      // ...
    }
    

    Das habe ich doch in mein code die ich oben opostet habe, schon mal versucht, der
    erzeugt eine neue object, ich will aber auf den alten bzw gleichen object benutze.

    void myClass::callBackFunction(myClass *arg ){
    
        myClass *mySelf = (myClass*) arg;
    


  • Du hast aber myClass* als Parameter und nicht void* .

    Übrigens:

    myClass *mySelf = (myClass*) arg;
    

    Hier würde ich C++-Castoperatoren nehmen:

    myClass* mySelf = static_cast<myClass*>(arg);
    


  • ich habe es gerade ausprobiert, es wird immer eine neue Object erzuegt:

    void myClass::callBackFunction(void *arg ){
    
        int id          = *((int *)arg);        // process ID
         myClass *mySelf = static_cast<myClass*>(arg);
        mySelf->flaeche();
    

    aber das glaube ich nicht andress seine, die Methode der VtkMultithreader Object
    SpawnThread() nur eine Signature einer void Funktion aufrufen kann, dh das object wird nicht mit rübergeben bzw. gespeichert


Anmelden zum Antworten