Probe ob ein virtual Member überladen wurde



  • Hallo,

    gibt es eine elegante Methode um zu überprüfen, ob eine Memberfunktion überladen wurde?

    Ich hab hier mal ein Beispiel und wollte wissen, ob dies so korrekt ist.

    #include <iostream>
    #include <stdio.h>
    
    using namespace std;
    
    class Base
    { 
    public: 
      virtual void WhoAmI() const; 
      virtual void get (int a);
      virtual void get (double b);
      virtual int calc (const int& a) const;
    };
    
    class Derived : public Base 
    { 
    public: 
      virtual void WhoAmI() const;
      virtual void get (double b);
    }; 
    
    void Base::WhoAmI() const { 
      cout << "I am the Base" << endl; }
    
    void Base::get (int a) {
      cout << "INT " << a << endl; }
    
    void Base::get (double b) {
      cout << "DOUBLE " << b << endl; }
    
    int Base::calc (const int& a) const {
      return a+a; }
    
    void Derived::WhoAmI() const { 
      cout << "I am the Derived" << endl; }
    
    void Derived::get (double b) {
      cout << "DERIVED DOUBLE " << b << endl; }
    

    Für die Überprüfung nehme ich dann Zeiger auf die Memberfunktionen und vergleiche die Adresse. Ist die Funktion nicht überladen, so sind die die Zeiger gleich.

    Base theBase;
    Derived *theDerived = new Derived;
    
    typedef void (Base::*getPtr) (double);
    typedef void (Base::*getPtr2) (int);
    
    getPtr f1 = &Base::get;
    getPtr2 f2 = &Base::get;
    
    if ((void *)(theBase.*f1) == (void *)(theDerived->*f1)) //Methode get (double) wurde überladen
      cout <<"error" << endl;
    else
      cout << "ok" << endl;
    
    cout << "----------------------------------------" << endl;
    
    if ((void *)(theBase.*f2) == (void *)((*theDerived).*f2)) /7Methode get (int) wurde nicht überladen
      cout <<"ok" << endl;
    else
      cout << "error" << endl;
    

    Ich erhalte dann beim kompilieren Warnungen und ich vermute das stimmt noch etwas nicht.

    main.cpp:81: warning: converting from ‘int (Base::)(const int&)const’ to ‘void*’
    main.cpp:81: warning: converting from ‘int (Base::)(const int&)const’ to ‘void*’

    Danke



  • Hallo,

    ein Zeiger auf eine Memberfunction muss keine Adresse beinhalten.
    Daher die Warnungen und daher ist der Ansatz auch zum Scheitern verurteilt.

    Eine Alternative weiß ich leider nicht (außer natürlich in den Überladungen irgendein Flag oder sowas zu setzen).



  • Die Frage sollte eher sein, warum du meinst eine mögliche Überladung identifizieren können zu müssen.
    Du kannst zur Compilezeit erzwingen, dass eine Methode überladen sein muss, indem du diese in der Basisklasse pure virtual deklarierst.



  • l'abra d'or schrieb:

    Die Frage sollte eher sein, warum du meinst eine mögliche Überladung identifizieren können zu müssen.
    Du kannst zur Compilezeit erzwingen, dass eine Methode überladen sein muss, indem du diese in der Basisklasse pure virtual deklarierst.

    Ja, dass sollte man machen.

    Das Problem ist aber, dass in der Basisklasse zwei Funktionen existieren, die sich nur in den Signaturen unterscheiden. In den jeweiligen Ableitungen wurde dann mal eine oder auch beide Methoden überladen.

    Ich hatte nun die Idee, dass ich über ein solches Konstrukt die Stellen finden könnte.



  • daishi schrieb:

    Das Problem ist aber, dass in der Basisklasse zwei Funktionen existieren, die sich nur in den Signaturen unterscheiden. In den jeweiligen Ableitungen wurde dann mal eine oder auch beide Methoden überladen.

    Überladung ändert ja nichts daran, dass pur virtuelle Funktionen in abgeleiteten Klassen implementiert werden müssen. Warum kannst du in deinem Beispiel nicht einfach void Base::get(int) als rein virtuell deklarieren?

    Kannst du vielleicht etwas mehr dazu sagen, warum jeweils beide Methoden gleichzeitig überladen sein sollen (vom Design her)?



  • Nexus schrieb:

    Kannst du vielleicht etwas mehr dazu sagen, warum jeweils beide Methoden gleichzeitig überladen sein sollen (vom Design her)?

    Eigentlich sollen nicht beide Methoden zur gleichen Zeit überladen sein, an einigen Stellen ist es aber passiert. Es handelt sich dabei eigentlich um eine Interfaceklasse.

    Das Design kann ich leider nicht so einfach Ändern und daher habe ich nach einer Möglichkeit gesucht, diese Stellen zu finden.



  • Klarer Fall für NVI 😛
    Genau eine nicht-öffentliche Virtuelle Funktion muss (kann) von den abgeleiteten Klassen implementiert werden. Die Basisklasse bietet in der öffentlichen Schnittstelle nicht-virtuelle Funktionen an (welche dann variierende Signatur haben können), und rufen passend die virtuelle Funktion auf. Damit garantierst du, dass wenn eine Überladung notwendig ist, diese auch immer korrekt benutzt wird, egal wie viele weitere Funktionen die benutzen müssen.



  • Ein NVI ist aber auch keine elegante Lösung.

    Da durch eine Reimplementierung der nicht-virtuellen Methode in einer abgeleiteten Klasse man in neue Probleme läuft.

    Mein Problem ist, dass ich mit diesem Konstrukt Fehler der Implementierung aufdecken will.



  • daishi schrieb:

    Mein Problem ist, dass ich mit diesem Konstrukt Fehler der Implementierung aufdecken will.

    Und warum soll das erst zur Laufzeit aufgedeckt werden?



  • daishi schrieb:

    Das Design kann ich leider nicht so einfach Ändern und daher habe ich nach einer Möglichkeit gesucht, diese Stellen zu finden.

    Wenns nur darum geht die Stellen zu finden, kannst du evtl in der Base::get() etwas ändern?

    dan könnte man zB über ein Singleton Flags setzen.

    zB ungefähr:

    class Flags : public Singleton
    {
    ...
    }
    void Base::get(int a)
    {
      ...
      #ifdef DEBUG
      Flags::Inst()->SetFlag(/*Get(int) nicht überladen*/);
      #endif
    }
    
    void Base::get(double a)
    {
      ...
      #ifdef DEBUG
      Flags::Inst()->SetFlag(/*Get(double) nicht überladen*/);
      #endif
    } 
    
    ...
    Base theBase;
    Derived *theDerived = new Derived;
    
    Flags::Inst()->ClearFlags();
    int x = 5;
    double y = 5.5;
    Derived->get(x);
    Derived->get(y);
    
    if (Flags::Inst()->GetFlags() == ... ) // Keine der beiden flags gesetzt?
      cout <<"error" << endl;
    else
      cout << "ok" << endl;
    
    cout << "----------------------------------------" << endl;
    

    hat bestimmt noch fehler drin. Aber so müsstest du "nur" in der Base-klasse etwas ändern.



  • Jockelx schrieb:

    Und warum soll das erst zur Laufzeit aufgedeckt werden?

    Zur Laufzeit ist nur eine Idee, wenn die Interfaceklasse. Da wie bereits gesagt es sich um eine Interfaceklasse handelt wollte ich die korrekte Implementierung erst bei der Verwendung prüfen.

    BigNeal schrieb:

    Wenns nur darum geht die Stellen zu finden, kannst du evtl in der Base::get() etwas ändern?

    dan könnte man zB über ein Singleton Flags setzen.

    Interessante Idee, ich werde es mal versuchen. DANKE.


Anmelden zum Antworten