Funktionszeiger an eine andere Klasse übergeben.



  • Hallo Leute,

    ist es möglich einen Funktionszeiger auf eine public Funktion der Klasse A (OpenGL-Klasse) an eine dritte Klasse (Event-Klasse) zu übergeben die keine keine Instanz der Klasse A führt?


  • Mod

    Ja, klar ist das möglich. Also das Übergeben des Zeigers*. Nur mit dem Aufrufen wird's halt schwierig.

    edit: Siehe zu dem Thema auch hier:
    http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2

    *: edit2: Natürlich nicht in Form eines einfachen Funktionszeigers. Memberfunktionszeiger und Funktionszeiger sind unterschiedliche Typen.



  • Hier ein Beispiel mit dem typedef und der Klasse deren Funktionen übergeben werden sollen.

    // A.h
    class A
    {
    ...
    public:
    typedef int(A::*funcPointer)(int,double)const;
    ...
    // Funktionen die übergeben sollen immer noch public
    int GetMyFuktionA(int id, double position) const;
    int GetMyFuktionB(int id, double position) const;
    
    }
    

    Hier die Eventklasse

    // B.h
    cllass B
    {
    public:
      B::B( ... , funcPointerA = 0, funcPointerB = 0, ...),
      : funcA(funcPointerA),funcB(funcPointerB), ...
    
      int GetInterestingA(int id) { return (*(*funcA))(id,pos.GetPan());
      int GetInterestingB(int id) { return (*(*funcB))(id,pos.GetTilt());
    
    private:
    Position pos;
    funcPointer *funcA;
    funcPointer *funcB;
    
    A::funcPointer & GetFuncA() const { return *funcA; }
    A::funcPointer & GetFuncB() const { return *funcB; }
    

    So in etwa habe ich mir es vorgestellt. Allerdings bin ich ein C++ Anfänger und kriege z.B. mit der Notation in Zeile 8-9 (*(*funcA)) .. Compiler Fehler.



  • funZeiger schrieb:

    So in etwa habe ich mir es vorgestellt. Allerdings bin ich ein C++ Anfänger und kriege z.B. mit der Notation in Zeile 8-9 (*(*funcA)) .. Compiler Fehler.

    *funcA dereferenziert den functionpoitner. *(*funcA) würde die Funktion dereferenzieren - was dem Compiler verständlicherweise spanisch vorkommt.

    Nichtstaische Memberfunktionen können nur auf Objekten ihrer Klasse aufgerufen werden. Wenn du kein A-Objekt hast, kannst du auch auf keinem Objekt GetMyFunctionA aufrufen. Auch nicht über Funktionspointer oder andere Ferkeleien 😉 Logisch oder?


  • Mod

    Und das ist eben genau das wie es nicht geht. funcA ist ohne Angabe eines konkreten Objekts völlig bedeutungslos und deswegen funktioniert der Aufruf auch nicht.

    Kannst du kurz beschreiben, was die Anforderungen an dein Programm sind? Dann kann man bestimmt eine Alternative basteln.



  • pumuckl schrieb:

    funZeiger schrieb:

    So in etwa habe ich mir es vorgestellt. Allerdings bin ich ein C++ Anfänger und kriege z.B. mit der Notation in Zeile 8-9 (*(*funcA)) .. Compiler Fehler.

    *funcA dereferenziert den functionpoitner. *(*funcA) würde die Funktion dereferenzieren - was dem Compiler verständlicherweise spanisch vorkommt.

    Nichtstaische Memberfunktionen können nur auf Objekten ihrer Klasse aufgerufen werden. Wenn du kein A-Objekt hast, kannst du auch auf keinem Objekt GetMyFunctionA aufrufen. Auch nicht über Funktionspointer oder andere Ferkeleien 😉 Logisch oder?

    Klingt so als müsste ich auch eine Instanz (this->Pointer der Klasse A) mit übergeben?



  • SeppJ schrieb:

    Und das ist eben genau das wie es nicht geht. funcA ist ohne Angabe eines konkreten Objekts völlig bedeutungslos und deswegen funktioniert der Aufruf auch nicht.

    Kannst du kurz beschreiben, was die Anforderungen an dein Programm sind? Dann kann man bestimmt eine Alternative basteln.

    Ich habe innerhalb der (OpenGL) Klasse A insgesamt n-Koordinatensysteme jeweils mit einer id versehen. Jedes Koordinatensystem ist unterschiedlich ausgedehnt und hat für Mausposition des Bildschirms eine andere Projektionsfunktion.

    Sobald ist die Maus bewegt sendet die Klasse A ein Event (Klasse 😎 mit einer allgemeinen Position (pos). Dieses Event wird von anderen Klassen abgefangen die jeweils nur ein Koordinatensystem interessiert. Die Umrechnung erfolgt mit den Funktionen

    int GetMyFuktionA(int id, double position) const;
    int GetMyFuktionB(int id, double position) const;
    

    wobei "double" damit es übersichtlich bleiben sollte. Bis hier ist alles implementiert und funktioniert soweit ganz gut.

    Nun wollte ich intern einen Funktionszeiger speichern damit ich nur dann umrechnen muss wenn es tatsächlich nötig ist. Bisher habe ich ein Array aus allen Systemen angelegt und mit in das Event gepackt.

    So wäre z.B. in der Klasse C so etwas gedacht.

    x = event.GetInterestingA(id_der_klasse_C);
    y = event.GetInterestingB(id_der_klasse_C);
    z = event.GetInterestingC(id_der_klasse_C);
    

  • Mod

    edit: Vielleicht sollte ich noch einmal gründlicher lesen.

    edit2: So, jetzt aber:
    Wenn ich richtig verstehe, ist diese id immer fest für eine bestimmt Klasse? Wenn ja, warum brauchst du dann überhaupt ids und Funktionszeiger? Ein Zeiger auf A wäre ausreichend und du könntest direkt die passende Funktion aufrufen.

    Aber nehmen wir mal an, dass du darüber schon nachgedacht hast und die id ist doch immer anders. Dann möchtest du vielleicht etwa so etwas:

    #include<iostream>
    
    using namespace std;
    
    class A
    {
    private:
      int data;
    public:
      A(int a): data(a){}
      void a(double pos) const {cout<<"a:"<<data+pos<< "\n";}
      void b(double pos) const {cout<<"b:"<<data-pos<< "\n";} 
      void c(double pos) const {cout<<"c:"<<data*pos<< "\n";}
    };
    
    typedef void (A::*Afunction)(double) const;
    
    class ACaller
    {
    private:
      A *a;
      Afunction af;
    public:
      ACaller(A* a, Afunction af):a(a), af(af){}
      void operator()(double pos){(*a.*af)(pos);}
    };
    
    class B
    {
    private:
      ACaller funcA, funcB, funcC;
      double pos;
    public:
      B(A* a, double pos): funcA(a, &A::a), funcB(a, &A::b),funcC(a, &A::c), pos(pos){}
      void callID(int id)
      {
        switch (id)
          {
          case 1: funcA(pos); break;
          case 2: funcB(pos); break;
          case 3: funcC(pos); break;
          default:
            cout<<"Flasche ID!\n";
          }
      }
    };
    
    int main()
    {
      A foo(100);
      B bar(&foo, 10);
      bar.callID(1);
      bar.callID(2);
      bar.callID(3);
    }
    

    Dies ist eine starke Vereinfachung des allgemeinen Functionoid-Konzepts, welches in dem Link den ich dir gegeben habe steht, angewandt auf Memberfunktionen.



  • SeppJ schrieb:

    ...

    Das sieht gut aus und scheint auf den ersten Blick das zu tun was ich brauche. Ich versuche es jetzt mal in mein System hineinzupacken. Danke für eure super Unterstützung!


  • Mod

    Wobei dies im Prinzip auch getan wäre, indem bar einen Zeiger auf foo hält. Der Unterschied ist hier, dass du im Prinzip auch verschiedene A haben kannst. Falls es immer das gleiche A ist, würde ich eher ersteres nehmen, weil dies nochmal wesentlich einfacher wäre.


Anmelden zum Antworten