function-pointer vs member-function-pointer



  • Ich habe ein Problem mit einer externen Bibliothek (OPT++). Um diese zu nutzen müssen sogenannte " User-Defined Functions" angegeben werden nach dem Muster:

    void (*USERFCN1)(mode, ndim, x, fx, gx, result):
    

    D.h. es sollen function-pointer übergeben werden. Die Funktion, welche ich gerne übergeben würde ist jedoch in einer Klasse enthalten, so dass ich nur member-function-pointer habe ...
    Eine mögliche Lösung wäre ja die Funktion als static zu deklarieren, was mir jedoch die ganze Klasse kaputt macht, da ich dann alle member als static deklarieren müsste 😞
    Welche anderen Lösungen könnte ich nutzen? Ich habe leider nicht die Möglichkeit die externe Bibliothek zu ändern 😡 , sonst wäre sicherlich boost::function und boost::bind eine Lösung ...

    Vielen Dank für Eure Hilfe



  • hmm.. gibts es einen unterschied zwischen funktionpointer und memberfunktionpointer???

    typedef void (*fktptr)(int a, double b) myfkt;
    
    class A{
    .
    .
    
    public:
    
     foo(int a,int b){
     ....
      }
    };
    
    myfkt t= A::foo;
    

    geht sowas in der art? hab aber keine ahnung von funktionpointer..



  • Ja leider gibt es einen Unterschied. Gegeben sei folgende Situation:

    int f(char a, double b);
    

    Der Typ der Funktion is unterschiedlich jenachdem ob es eine normale Funktion ist oder eine non-static member-function aus irgendeiner Klasse:

    [] für normale (main) Funktionen ist der Typ: int ()(char,double)
    [] für eine non-static member Funktion der Klasse Paul: int (Paul::)(char,double)

    Nur wenn die Funktion in der Klasse Paul static ist, ist der Typ gleich zu der normalen Funktion: int (*)(char,double)



  • BorisDieKlinge schrieb:

    hmm.. gibts es einen unterschied zwischen funktionpointer und memberfunktionpointer???

    Memberfunktionen haben immer implizit den this-Zeiger ihren Objekts als Parameter enthalten. Also ja, es gibt einen Unterschied.



  • @Tachyon: Stimmt, man lernt nie aus...

    @teddybär: ne schnittestellen klasse zwischzen deinen fktptr's und deinen klassen?



  • Wie die Lösung am Ende ausschaut ist fast egal. Ich habe halt folgende Situation:

    class myclass{
    private:
      void do_something(parameter);
      int some_data;
      ...
    public:
      void my_func(mode, ndim, x, fx, gx, result);
    }
    

    und die externe Bib will ja nen pointer

    void (*USERFCN1)(mode, ndim, x, fx, gx, result);
    

    am liebsten würde ich der Bib nun übergeben:

    &myclass::my_func
    

    nur das ist eben ein member-function-pointer 😞
    und die my_func kann ich nicht static machen, da ich sonst keinen Zugriff mehr auf do_something und some_data habe ...



  • class A{
    
    	int m_i;
    public:
    	A(int i): m_i(i){}
    
    	void foo(int i){
    
    	}
    };
    
    static A *ptmp=NULL;
    static void foo(int i){
    if(ptmp)ptmp->foo(i);
    }
    int main(){
    A o(5);
    ptmp= &o;
    return 0;
    }
    


  • BorisDieKlinge schrieb:

    class A{
    
    	int m_i;
    public:
    	A(int i): m_i(i){}
        
    	void foo(int i){
    		
    	}
    };
    
    static A *ptmp=NULL;
    static void foo(int i){
    if(ptmp)ptmp->foo(i);
    }
    int main(){
    A o(5);
    ptmp= &o;
    return 0;
    }
    

    das wuerde jedoch nur funktionieren wenn er von seiner klasse nur eine instanz erzeugt.

    Meep Meep



  • Meep Meep schrieb:

    BorisDieKlinge schrieb:

    class A{
    
    	int m_i;
    public:
    	A(int i): m_i(i){}
        
    	void foo(int i){
    		
    	}
    };
    
    static A *ptmp=NULL;
    static void foo(int i){
    if(ptmp)ptmp->foo(i);
    }
    int main(){
    A o(5);
    ptmp= &o;
    return 0;
    }
    

    das wuerde jedoch nur funktionieren wenn er von seiner klasse nur eine instanz erzeugt.

    Meep Meep

    Warum?



  • static A *ptmp=NULL;
    
    static void foo(int i)
    {
       if(ptmp)
          ptmp->foo(i);
    }
    
    int main()
    {
       A o(5);
       ptmp= &o;
       return 0;
    }
    

    er verwendet den zeiger ptmp als pseude singleton. dem kann er immer nur eine instanz der klasse zuweisen.

    void foo(int) ist die callback-func. die ueberprueft ob der zeiger ptmp auf ein objekt zeigt und ruft dann eine meber-func auf.

    solange es fuer teddybär ausreichend ist, mit nur einer instanz seiner klasse zu arbeiten, ist der loesungsansatz recht gut.
    vielleicht sollte ich sagen 'nur eine instanz der klasse die mit OPT++ zum jeweiligen zeitpunkt zusammenarbeiten kann'.

    Meep Meep



  • Meep Meep schrieb:

    static A *ptmp=NULL;
    
    static void foo(int i)
    {
       if(ptmp)
          ptmp->foo(i);
    }
    
    int main()
    {
       A o(5);
       ptmp= &o;
       return 0;
    }
    

    er verwendet den zeiger ptmp als pseude singleton. dem kann er immer nur eine instanz der klasse zuweisen.

    void foo(int) ist die callback-func. die ueberprueft ob der zeiger ptmp auf ein objekt zeigt und ruft dann eine meber-func auf.

    solange es fuer teddybär ausreichend ist, mit nur einer instanz seiner klasse zu arbeiten, ist der loesungsansatz recht gut.

    Meep Meep schrieb:

    vielleicht sollte ich sagen 'nur eine instanz der klasse die mit OPT++ zum jeweiligen zeitpunkt zusammenarbeiten kann'.

    Das ^^ ist der entscheidende Satz!

    Er kann natürlich for jedem Aufruf der Funktion, die seine Funtktion als Callback verwendet, den Zeiger umsetzen.



  • Mal 'ne Erweiterung von Boris' Variante:

    //interface
    typedef void (*fun)(int, double);
    
    //Funktion, die globalen FktPtr haben will
    void callFun(fun function)
    {
        function(42, 3.14159f);
    }
    
    class MyClass
    {
    public:
        //ruft callFun fuer dieses Objekt auf
        void callCFun()
        {
            //wenns threadsafe sein soll, hier synchronisieren!
            currentCallObj = this;
            callFun(&interfaceFun);
        }
    
    private:
        //die problematische, nichtstatische Funktion
        void evilMember(int i, double d)
        {
            std::cout << i << "    " << d << '\n';
        }
    
        static MyClass* currentCallObj;
        //Interface auf statische Funktion
        //ggf. extern "C"!
        static void interfaceFun(int i, double d)
        {
            currentCallObj->evilMember(i, d);
        }
    };
    MyClass* MyClass::currentCallObj;
    
    int main()
    {
        MyClass a;
        a.callCFun();
    }
    


  • Vielen vielen Dank für die schnellen Antworten. Ich werde all diese mal testen und dann sehen, ob das für mein Problem brauchbar ist. Bis denne ...



  • So nun habe ich mal ein paar Tests gemacht und muss leider feststellen, dass die Lösung scheinbar nicht anzuwenden ist. Mein Problem ist die externe lib OPT++, die Klasse welche ich verwenden will, hat nen Constructor vom Typ:

    OPTPP::FDNLF1(int ndim, USERFCN0 f, INITFCN i)
    

    mit

    typedef void (*INITFCN)(int, NEWMAT::ColumnVector&);
    typedef void (*USERFCN0)(int, const NEWMAT::ColumnVector&, real&, int&);
    

    Für die beiden Funktionspointer INITFCN und USERFCN0 will ich nun Funktionen aus meiner Klasse nehmen

    class my_class
    {
     public:
      // die problematischen Funktionen, welche ich NICHT als static annehmen kann
    
      void init_fcn(int n, NEWMAT::ColumnVector& x);
      void fcn0(int n, const NEWMAT::ColumnVector& x, double& fx, int& result);
    
     public:
    
      my_class(){}
      virtual ~my_class(){}
    };
    

    D.h. ich würde am liebsten schreiben

    int main ()
    {
      int n = 2;
    
      //  Create an object of OPT++ using my_class functions
    
      OPTPP::FDNLF1 nlp(n, &my_class::fcn0, &my_class::init_fcn);
    
      // oder alternativ
    
      my_class A;
      FDNLF1 nlp(n, &A.fcn0, &A.init_fcn);
    
      return 0;
    }
    

    dies geht jedoch nur, wenn ich die Funktionen init_fcn und fcn0 in my_class als static kennzeichne 😡

    leider sehe ich nicht, wie ich Eure Ratschläge hier umsetzen sollte ...



  • Wenn ich mir OPT++ so ansehe, frage ich mich, wo der Sinn darin liegt, dass Deine Funktion in einer Klasse liegt.



  • Ich habe mein ganzes Programm in C++ geschrieben und durchweg objekt-orientiert gearbeitet. Es gibt also eine Klasse, welche das komplette Management übernimmt und dazu gehören u.a. die Funktionen init_fcn und fcn0 - diese beschrieben nicht einfach eine Funktion, welche ausgewertet werden soll, sondern stoßen weitreichende Berechnungen an (komplette FEM Simulation z.B.) ...
    D.h. die Funktionen init_fcn und fcn0 sind nicht einfach "handcoded", sondern stehen für einen Anruf einer anderen software (z.B. FEM Simulation). Ich denke, dass es daher unmöglich ist diese Funktionen nicht in einer Klasse zu kapseln.



  • teddybär schrieb:

    Ich habe mein ganzes Programm in C++ geschrieben und durchweg objekt-orientiert gearbeitet. Es gibt also eine Klasse, welche das komplette Management übernimmt und dazu gehören u.a. die Funktionen init_fcn und fcn0 - diese beschrieben nicht einfach eine Funktion, welche ausgewertet werden soll, sondern stoßen weitreichende Berechnungen an (komplette FEM Simulation z.B.) ...
    D.h. die Funktionen init_fcn und fcn0 sind nicht einfach "handcoded", sondern stehen für einen Anruf einer anderen software (z.B. FEM Simulation). Ich denke, dass es daher unmöglich ist diese Funktionen nicht in einer Klasse zu kapseln.

    Wieso? Die FEM Simulation kann doch ein lokales Objekt in Deiner CB-Funktion sein.



  • was meinst Du denn mit "CB-Funktion" ???

    Vielleicht sollte ich meine Situation anders formulieren: ich habe mir eine software geschrieben, welche verschiedene Optimierungsalgorithmen bereitstellt. Diese möchte ich nun um ein OPT++ Interface erweitern, d.h. der grobe Ablauf des Programmes ist bereits fest und dazu gehört auch, dass das Interface zur Funktionsauswertung in einer eigenen Klasse liegt (diese Klasse ist selber eine Art wrapper für andere software).



  • teddybär schrieb:

    was meinst Du denn mit "CB-Funktion" ???

    Callback Funtion.



  • und wie soll ich die FEM-software initialisieren, wenn diese innerhalb einer "globalen" Funktion steckt? Ich muss in der main zuerst eine komplette Initialisierung der FEM-software durchführen (also eine spezielle Klasse daraus deklarieren) und kann erst dann eine spezielle member-Funktion dieser FEM-Klasse ansprechen, welche die Auswertung durchführt ...
    Und OPT++ braucht nunmal einen pointer auf genau diese Funktion



  • Du könntest eine freie Funktion verwenden und der dann eine Instanz dieser Initialisierungsklasse übergeben (die für Übergabe dann binden) oder die Funktion nutzt eine globale Instanz dieser Klasse.


Anmelden zum Antworten