Funktionszeiger auf Memberfunktion



  • Kann man eigentlich nen Methodenzeiger in nen Funktionszeiger "casten"?



  • mal so schrieb:

    Kann man eigentlich nen Methodenzeiger in nen Funktionszeiger "casten"?

    Was bringts dir?



  • mal so schrieb:

    Kann man eigentlich nen Methodenzeiger in nen Funktionszeiger "casten"?

    Man kann zwar viel böse rumcasten, aber das würde der Compiler IMHO in jedem denkbaren Fall verhindern.



  • HerrLatz schrieb:

    ...kann es sein daß ich eine Memberfunktion nicht per Funktionspointer übergeben kann, weil dann die beziehung zum speziellen Objekt verloren geht?...

    👍
    Also ich finde es super, dass Du da alleine drauf gekommen bist ! (ganz ernst gemeint)
    In fast allen anderen Threads zu diesem Thema liegt der Grund genau darin, dass die Leute diesen Zusammenhang nicht beachtet haben.

    Als mögliche "Lösungen" Zu Deinem Beispiel fallen mir ein: Lösungsverfahren() nimmt als Parameter

    • ein "Gleichungssystem" oder
    • eine gemeinsame Basisklasses (z.B. class hasWertFunktion ) oder
    • einen Funktor

    entgegen.
    Zum Letzten:

    void Loesungsverfahren(void (*)(Vec&, Vec&));
    
    struct Gleichungssystem
    {
        Vec anfangswert;
    
        void Wert(Vec &in, Vec &out);
    
        void Solve();
    }
    
    struct Wert_Funktion {
       Gleichungssystem& g;
       Wert_Funktion(Gleichungssystem& bezug) : g(bezug) {}
       void operator()(Vec &in, Vec &out) { g.Wert(in, out); }
    };
    
    Gleichungssystem::Solve()
    {
       Wert_Funktion  wf(*this);
       Loesungsverfahren(wf);
    }
    

    Der Funktor "Wert_Funktion" "merkt" sich also den Bezug zum Objekt.

    Gruß,

    Simon2.

    P.S.: Den Zugriff auf Klassenmember mittels "this->" finde ich unübersichtlich, überflüssig und "de-flexibilisierend". 😉



  • @Simon2: Hmmm. Die Funktion Loesungsverfahren nimmt einen Funktionszeiger entgegen, und Du gibst ihm einen Funktor.

    Eine mögliche Lösung (ohne tr1) wäre, den Funktor als Template zu realisieren. Wenn die Signatur nicht stimmt, wird sich der Compiler schon beschweren 😉

    template<typename Func>
    void Loesungsverfahren(Func f)
    {
    // hier f als funktion nutzen
        f(x,y);
    }
    
    struct Gleichungssystem
    {
        Vec anfangswert;
    
        void Wert(Vec &in, Vec &out);
    
        void Solve();
    };
    
    struct Wert_Funktion {
        Gleichungssystem& g;
        Wert_Funktion(Gleichungssystem& bezug) : g(bezug) {}
        void operator()(Vec &in, Vec &out) { g.Wert(in, out); }
    };
    
    void Gleichungssystem::Solve()
    {
        Wert_Funktion  wf(*this);
        Loesungsverfahren(wf);
    }
    


  • Wow, auf jeden Fall vielen Dank für die vielen Antworten.
    Das Lösungsverfahren liegt im Quellcode vor, insofern kann ich das schon verändern. Ich wollte es zwar ursprünglich lassen wie es ist, aber ich vermute so geht es einfacher.
    Im Moment ist meine präferierte Lösung das übergeben einer Basisklasse, da ich so keinen Zirkelbezug bekomme. Den Begriff Funktor habe ich heute zum ersten mal gehört und nicht viel dazu im Netz gefunden. Das hier war zwar interessant, hat aber wenig weitergeholfen:
    Funktor
    Werde aber noch ein wenig rumschaun.



  • Ja, die Seite redet ja auch nur ganz knapp über C++ Funktoren 😉

    Kurz zusammengefasst das wichtigste: Ein Funktor (oder Funktionsobjekt) ist ein Objekt, das wie eine Funktion verwendet werden kann. Das bedeutet letztendlich nur, daß die entsprechende Klasse den operator() überladen hat. (aber da sich dahinter ein vollwertiges Objekt befindet, ist ein Funktor um einiges mächtiger als eine normale Funktion).



  • Ok, jetzt hats geschnaklt. Das klingt eleganter als eine spezielle Basisklasse einzuführen.
    Vielen Dank euch allen,
    Matthias



  • Ich bin jetzt den Weg mit dem Template gegangen. Das sieht dann in etwa so aus:

    // Datei nr.h
    template<typename Func>
    void broydn(Func f);
    
    // Datei broydn.cpp. Das ist das Lösungsverfahren.
    include "nr.h"
    template<typename Func>
    void broydn(Func f)
    {
    // hier f als funktion nutzen
        f(x,y);
    }
    
    // Datei Gleichungssystem.h
    #include "nr.h"
    struct Gleichungssystem
    {
        Vec anfangswert;
    
        void Wert(Vec &in, Vec &out);
    
        void Solve();
    };
    
    // Datei Gleichungssystem.cpp
    struct Wert_Funktion {
        Gleichungssystem& g;
        Wert_Funktion(Gleichungssystem& bezug) : g(bezug) {}
        void operator()(Vec &in, Vec &out) { g.Wert(in, out); }
    };
    
    // Datei Gleichungssystem.cpp
    void Gleichungssystem::Solve()
    {
        Wert_Funktion  wf(*this);
        Loesungsverfahren(wf);
    }
    

    Jetzt bekomme ich aber folgenden Fehler:

    error LNK2019 unresolved external symbol "void __cdecl broydn<struct Wert_Funktion>...
    

    Jetzt hab ich irgendwie nicht so recht eine Ahnung woran das liegt. Kann mir da nochmal jemand auf die Sprünge helfen?
    Danke,
    Matthias



  • HerrLatz schrieb:

    ...

    // Datei nr.h
    template<typename Func>
    void broydn(Func f);
    
    // Datei broydn.cpp. Das ist das Lösungsverfahren.
    include "nr.h"
    template<typename Func>
    void broydn(Func f)
    {
    // hier f als funktion nutzen
        f(x,y);
    }
    ...
    

    Geht nicht !
    Der Compiler muss die Implementation eines templates sehen =>

    // Datei nr.h
    template<typename Func>
    void broydn(Func f)
    {
    // hier f als funktion nutzen
        f(x,y);
    }
    

    Ist übrigens der Standardfehler bei template-Anfängern 😉 ...

    Gruß,

    Simon2.


Anmelden zum Antworten