Pointer auf Funktion



  • Hallo.

    Ich habe folgendes Codefragment und eine Fehlermeldung dazu. Meine Fragen formuliere ich im Anschluss.

    class X {
    public:
      void die();
    protected:
      void (*pBreakCallFunction)();
    
    ...
    
    }
    
    X::X(){
      this->pBreakCallFunction = &X::die;
    }
    
    void X::die(){
      // do something...
    }
    

    Fehlermeldung (manuell angepasst):

    X.cpp:12: Fehler: »void (X::*)()« kann nicht nach »void (*)()« in assignment umgewandelt werden
    

    Variante 1: Ich habe bereits in Erfahrung gebracht / erfolgreich getestet, dass es mit einer entsprechenden Deklaration keine Meldung gibt:

    void (X::*pBreakCallFunction)();
    

    Variante 2: Die andere Variante, die ich getestet hatte (alternativ) war, bei der Zuweisung einen Typecast durchzuführen - dies brachte (nur) eine Warnung:

    this->pBreakCallFunction = (void (*)())&X::die;
    

    Nun mein Problem:
    Mein Ziel ist eigentlich dem Nutzer von Klasse X die Entscheidung frei zu überlassen, wo die Funktion herkommt, die er (bspw. ueber eine weitere public-Funktion) in der Membervariable hinterlegt, solange sie void liefert und keine Parameter besitzt...

    Mit Variante 1 dürfte ich dies nicht erreichen können (bspw. Funktionen anderer nicht von X erbender Klassen oder aus dem Hauptprogramm würden dies ja nicht erfüllen).
    Ob Variante 2 überhaupt bei einem kompilierten Programm funktioniert weiss ich Stand heute nicht mal.

    Daher meine Fragen:
    Können bei Variante 1 erbende Klassen eigene Funktionen überhaupt dort hinterlegen?
    Wie stelle ich es richtig an, dass ich das volle Ziel erreiche?

    Vielen Dank allen schon mal im Voraus!



  • Normale Funktionszeiger != Memberfunktionszeiger !!!
    Memberfunktionen benötigen ja ein konkretes Objekt.

    Ansonsten sieh dir mal boost::function<> an...



  • Die ursprüngliche Deklaration des Funktions-Pointers ist die einer freien Funktion. Das Casten auf eine Member-Funktion funktioniert zwar, beim Aufruf dürfte es aber gemeine Sachen zu beobachten geben.

    Die zweite Deklaration definiert dann einen Zeiger auf eine Member-Funktion von X. Den können auch Unterklassen mit einer eigenen Funktion setzen, die es in X selbst noch gar nicht gibt.

    Natürlich musst du die Funktion, je nach verwendetem Pointer, auch passend aufrufen. Aber das sagt dir der Compiler dann schon.

    Statt Variante 2 würde ich mir überlegen, ob es nicht auch eine rein virtuelle Funktion in Klasse X tut, die Unterklassen passend überschreiben müssen.

    Falls du eine allgemeingültige Lösung wünscht, kommst du mEn um Templates nicht herum. Aus dem Handgelenk fällt mir etwa folgende Lösung ein (Achtung: nicht getestet!):

    struct CallbackBase {
    
       virtual void call() = 0;
    };
    
    template <typename Fn>
    struct Callback: public CallbackBase {
    
       Fn fn;
    
       explicit Callback(Fn f) : fn(f) {
       }
    
       virtual void call() {
          fn();
       }
    };
    
    class X {
    
    public:
       template <typename C>
       void setCallback(C cb) {
          callback = std::auto_ptr<CallbackBase>(new Callback<C>(cb));
       }
    
    private:
       std::auto_ptr<CallbackBase> callback;
    };
    

    Stefan.



  • Ich verweise mal auf das berühmte Function Pointer Tutorial:

    http://www.newty.de/fpt/index.html

    Da steht sehr viel drin, was oft gebraucht wird.



  • Danke Euch allen!

    @Stefan die Problematik die ich beschrieben habe, war leider nur eine weniger komplizierte Ausführung dessen, was wirkilch vor mir stand. Tatsächlich ist auch die Menge der Zeiger je Subklasse unterschiedlich, die auf solche Funktionen gesetzt werden sollen. Bei dem Beispiel gings mir eher um die prinzipielle Vorgehensweise einen Funktionszeiger zu belegen.

    @drakon: Danke, die Doku hatte mich auf meinen Weg im Vorfeld gebracht 😃

    Allgemein kann ich hiermit sagen, dass meine Variante 1 so weit mittlerweile erfolgreich auch bei Subklassen angewendet wurde. Auch wenn ich manuell an dieser Stelle auf (void (X::*)())&XSub::fkt casten musste/muss.

    Schönes Wochenende zusammen


Anmelden zum Antworten