pointer-to-member-function aus einer anderen Klasse



  • Halli hallo,
    ich sitze gerade schon seit Stunden an einem Problem mit einem Funktionspointer auf eine member-Function.
    Die folgende Struktur nutze ich derzeit :

    Ich habe eine Klasse MyClass mit der Funktion
    calcAcceleration

    class MyClass {
        public :
            typedef vector3 (MyClass::*FPTR)(vector3);
    
            vector3 calcForce(vector3 previousSpeed_) {
                return 10 + 10 * previousSpeed_ / 2;
            }
    
            vector3 calcAcceleration(vector3 previousSpeed_) {
                double mass = 100;
                return calcForce(previousSpeed_) / mass;
            }
    
    };
    

    Diese Funktion soll in einer anderen Klasse NumericIntegrator von der Funktion integrateOneTimeStepEulerCauchy aufgerufen werden:

    enum IntegrationType {EULER_CAUCHY, HEUN, RUNGE_KUTTA, DORMAND_PRINCE};
    
    class NumericIntegrator
    {
        public:
            NumericIntegrator() {};
            ~NumericIntegrator() {};
            vector3 integrateOneTimeStep(double lengthOfTimeStepInSeconds_, IntegrationType integrationType_, vector3 previousValue_);
    
            // function Pointer
            void setFunctionToIntegrate(MyClass::FPTR functionToIntegrate_);
            vector3 callFunctionToIntegrate(vector3 param1_);
    
        private:
            vector3 integrateOneTimeStepEulerCauchy  (double lengthOfTimeStepInSeconds_, vector3 previousValue_);
            MyClass::FPTR functionToIntegrate;
    
    };
    

    Um mir das ewige weiterreichen des Funktionspointers als Parameter zu ersparen, habe ich mir gedacht, dass ich mit setFunctionToIntegrate den Pointer speichern kann :

    void NumericIntegrator::setFunctionToIntegrate(MyClass::FPTR val_) {
        functionToIntegrate = val_;
    };
    

    und den Aufruf der Funktion dann über die Funktion callFunctionToIntegrate durchführe.

    vector3 NumericIntegrator::callFunctionToIntegrate(vector3 param1_) {
        vector3 temp = (this->*functionToIntegrate)(param1_);
        return temp
    };
    

    Hierbei bekomme ich jedoch leider bereits beim kompilieren immer den folgenden Fehler :

    error pointer to member type 'vector3 (MyClass::)(vector3)' incompatible with object type 'NumericIntegrator'

    Kennt sich hier zufällig jemand aus?
    Ich habe schon sämtliche Foren durchwühlt, aber leider nichts finden können.
    Über eine Antwort würde ich mich sehr freuen 🙂

    viele Grüße
    anon1234



  • anon1234 schrieb:

    vector3 NumericIntegrator::callFunctionToIntegrate(vector3 param1_) {
        vector3 temp = (this->*functionToIntegrate)(param1_);
        return temp
    };
    

    Statt this brauchst du bei dem Aufruf ein Objekt von MyClass .



  • Um mir das ewige weiterreichen des Funktionspointers als Parameter zu ersparen, habe ich mir gedacht, dass ich mit setFunctionToIntegrate den Pointer speichern kann:

    Hmm, ok, kann man so machen -- finde ich vom Design her aber alles nicht so prickelnd.

    Hierbei bekomme ich jedoch leider bereits beim kompilieren immer den folgenden Fehler :

    error pointer to member type 'vector3 (MyClass::)(vector3)' incompatible with object type 'NumericIntegrator'

    Ja, die Fehlermeldung kommt, weil du mit dem this->* versuchst, die Methode auf dem NumericIntegrator statt auf deinem MyClass-Objekt aufzurufen.

    In dem Funktionszeiger ist nicht die Information enthalten, auf welchem Objekt du die Methode aufrufen willst.

    Edit: Oh, da war jemand schneller ... Aber: Nochmal was zum Design: Ich würde versuchen, soweit es geht, ohne Klassen auszukommen. Eigentlich sind das alles nur Funktionen in deinem Fall. Gut, man kann in der Klasse noch Parameter oder sowas mit reinstecken. Dann sind das aber immer noch "Funktionsobjekte".



  • Vielen Dank für eure super schnelle Hilfe 🙂
    Ich habe jetzt erst einmal in der Klasse noch einen Pointer auf mein Objekt gespeichert.

    Sieht dann entsprechend so aus :

    enum IntegrationType {EULER_CAUCHY, HEUN, RUNGE_KUTTA, DORMAND_PRINCE};
    
    class NumericIntegrator
    {
        public:
            NumericIntegrator() {};
            ~NumericIntegrator() {};
            vector3 integrateOneTimeStep(double lengthOfTimeStepInSeconds_, IntegrationType integrationType_, vector3 previousValue_);
    
            // function Pointer
            void setFunctionToIntegrate(MyClass::FPTR val_);
            void setObjectOfFunctionToIntegrate(MyClass *val_);
            vector3 callFunctionToIntegrate(vector3 param1_);
    
        private:
            vector3 integrateOneTimeStepEulerCauchy  (double lengthOfTimeStepInSeconds_, vector3 previousValue_);
            MyClass::FPTR functionToIntegrate;
            MyClass *objectOfFunctionToIntegrate;
    
    };
    
    vector3 NumericIntegrator::integrateOneTimeStep(double lengthOfTimeStepInSeconds_, IntegrationType integrationType_, vector3 previousValue_) {
        vector3 nextValue;
        switch(integrationType_) {
            case EULER_CAUCHY   : nextValue = integrateOneTimeStepEulerCauchy (lengthOfTimeStepInSeconds_,previousValue_); break;
        }
        return nextValue;
    };
    
    vector3 NumericIntegrator::integrateOneTimeStepEulerCauchy  (double lengthOfTimeStepInSeconds_, vector3 previousValue_) {
        vector3 nextValue = previousValue_ + lengthOfTimeStepInSeconds_ * callFunctionToIntegrate(previousValue_);
        return nextValue;
    };
    
    // function pointer
    void NumericIntegrator::setFunctionToIntegrate(MyClass::FPTR val_) {
        functionToIntegrate = val_;
    };
    
    void NumericIntegrator::setObjectOfFunctionToIntegrate(MyClass *val_) {
        objectOfFunctionToIntegrate = val_;
    };
    
    vector3 NumericIntegrator::callFunctionToIntegrate(vector3 param1_) {
        vector3 temp = (*objectOfFunctionToIntegrate.*functionToIntegrate)(param1_);
        return temp;
    };
    
    class MyClass {
        public :
            typedef vector3 (MyClass::*FPTR)(vector3);
    
            vector3 calcForce(vector3 previousSpeed_) {
                return 10 + 10 * previousSpeed_ / 2;
            }
    
            vector3 calcAcceleration(vector3 previousSpeed_) {
                double mass = 100;
                return calcForce(previousSpeed_) / mass;
            }
    
    };
    
    int main() {
        MyClass MC;
        NumericIntegrator NI;
        NI.setFunctionToIntegrate(&MyClass::calcAcceleration);
        NI.setObjectOfFunctionToIntegrate(&MC);
        vector3 temp =  NI.integrateOneTimeStep(0.001,IntegrationType::EULER_CAUCHY,{.x = 0.0, .y = 0.0, .z = 0.0});
        temp.setPrintPrecision(10);
        cout << temp;
    }
    

    Es funktioniert jetzt, allerdings habe ich nicht ganz verstanden, warum ich

    vector3 temp = (*objectOfFunctionToIntegrate.*functionToIntegrate)(param1_);
    

    statt

    vector3 temp = (*objectOfFunctionToIntegrate->*functionToIntegrate)(param1_);
    

    schreiben muss? Wisst ihr das zufällig?

    Und das mit dem Design, kann sehr gut sein, dass das nicht optimal ist.
    Da bin ich für Kritik aber gerne immer offen.
    Wie würdet ihr es umsetzen?
    So wie ich krümelkacker verstanden hab, würdet ihr ohne Klassen arbeiten um nicht mit member-functions arbeiten zu müssen richtig??
    In Wirklichkeit ist meine Klasse allerdings deutlich größer mit einigen mehr an Funktionen und Datenstrukturen drin, auf denen meine Funktion die ich übergeben will arbeitet. Dann macht das wieder nicht mehr so viel Sinn oder?
    Wie gesagt korrigiert mich gerne, wenn ich falsch liege 🙂

    Und noch einmal vielen Dank für die Hilfe
    gruß anon1234



  • anon1234 schrieb:

    Es funktioniert jetzt, allerdings habe ich nicht ganz verstanden, warum ich

    vector3 temp = (*objectOfFunctionToIntegrate.*functionToIntegrate)(param1_);
    

    statt

    vector3 temp = (*objectOfFunctionToIntegrate->*functionToIntegrate)(param1_);
    

    schreiben muss? Wisst ihr das zufällig?

    Aus dem gleichen Grund wieso man das auch bei Membern braucht:

    Someclass* s;
    s->x = 5;  // Entweder so
    (*s).x = 5;  // Oder so
    (*s)->x = 5;  // So nicht!
    


  • Someclass* s;
    s->x = 5;  // Entweder so
    (*s).x = 5;  // Oder so
    

    Sind die beiden Varianten identisch? Bzw wo ist der unterschied?



  • s->a = 5; // einfach zu schreiben
    (*s).a = 6; // vergleichsweise kompliziert zu schreiben
    *s.a = 7; // vor allem, da das hier etwas anderes ist
    

Anmelden zum Antworten