Basisklassenmethode in abgeleiteter Klasse überladen - Wie?



  • Ich bin ein bisschen überascht, das folgendes nicht geht:

    class CBase
    {
    public:
      void a() {;};
    };
    
    class CChild  :public CBase
    {
    public:
      void a(int i) {;};
    };
    
    int main()
    {
      CChild Child;
      Child.a();
    }
    

    Die Überladung a(int i) von CChild scheint das a() zu überdecken. Aber warum a() und a(int i) sind doch zwei völlig verschiedene Schuhe (und im grunde ist es für den Compiler doch genauso unterschiedlich wie a() und b(int i) 😕



  • Hallo,
    Überladung funktioniert immer nur auf der Ebene eines Sichtbarkeitsbereichs. Nie über die Grenzen einen solchen hinaus. Da sowohl CBase, als auch CChild eigene Scopes besitzen, findet hier keine Überladung sondern eine Überdeckung statt.
    Die Lösung:
    Befördere a in den Scope von CChild. Dies geschieht über eine using-Deklaration.
    Hier findest du mehr: http://fara.cs.uni-potsdam.de/~kaufmann/index.php?page=GenCppFaqs&faq=Overload#Answ

    [ Dieser Beitrag wurde am 08.01.2002 um 14:50 Uhr von HumeSikkins editiert. ]



  • Wird über eine solche Instanz eine Methode aufgerufen, schaut der Compiler 
    als erstes in den Scope der Klasse. Da er hier eine Methode Func findet, endet die Namensauflösung. Weitere Scopes werden 
    nicht mehr berücksichtig. Tatsächlich überdeckt Func aus Derived also Func aus Base.
    

    Naja, aber in meinem Fall findet sich ja keine passende Methode im Scope von CChild. Das müsste er sich doch automatisch denken, dass man da ja noch bei CBase nachgucken könnte images/smiles/icon_rolleyes.gif - stattdessen krieg ich nen Fehler

    [ Dieser Beitrag wurde am 11.12.2001 um 11:43 Uhr von kartoffelsack editiert. ]



  • Das verhalten ist schon ganz richtig so. Überschreibe ich die funktion einer klasse, so hat das meißt seinen grund. Diese funktion wird meißt anders arbeiten als die der basisklasse. In der Basisklasse gibt es z.b. ein f(int), in der abgeleiteten klasse ein f(unsigned). Jetzt kommt folgendes:

    class CBase
    {
    public:
      void a(int) {;};
    };
    
    class CChild   :public CBase
    {
    public:
      void a(unsigned) {;};
    };
    
    int main()
    {
      CChild Child;
    
      int a = 5;
      unsigned b = 6;
    
      Child.a(a+b);  // Welche funktion ist gemeint?
    }
    

    Welche funktion soll ausgeführt werden? Auf jeden fall hat das f der basis die bessere übereinstimmung - Funktionen überläd man jedoch gerade wegen veränderter funktionalität. Im oben angegebenen beispiel ist der typ von a+b eindeutig (?), ist aber schwer zu erkennen. Der programmierer wundert sich dann nachher, das die falsche funktion aufgerufen wird. An einen cast um den funktionsaufruf eindeutig zu machen denkt man in dem augenblick wohl nicht. Aus sicherheitsgründen hat man daher gleich alle funktionen der basis (wenn sie überschrieben werden) ausgeknipst. Aber es gibt eine möglichkeit funktionen der basisklasse trotzdem weiterhin zu zulassen.

    class CBase
    {
    public:
      void a() {;};
    };
    
    class CChild   :public CBase
    {
    public:
      void a(int i) {;};
      using CBase::a;  // <- so geht es auch
    };
    
    int main()
    {
      CChild Child;
      Child.a();
    }
    

    Eine explizite using-anweisung hilt in diesem beispiel.

    [ Dieser Beitrag wurde am 11.12.2001 um 11:55 Uhr von tunichtgut editiert. ]



  • @kartoffelsack
    Namensauflösung basiert zunächst erstmal nur auf dem Methodenname (hier also nur a). Erst ein Schritt später wird die am besten passende Methode ausgewählt (basierend auf der kompletten Signatur).
    Allgemein geht es immer so:

    1. Suche alle sichtbaren Namen (nur Name der Funktion)
    Namen eines Scopes verdecken die Namen eines darüberliegenden Scopes.
    2. Wähle alle aufrufbaren Funktionen (anhand der Signatur).
    3. Wähle die beste Übereinstimmung.

    Situation 1 (dein Beispiel):
    1. Suche alle sichtbaren Namen:
    Die Methode CChild::a ist die einzig sichtbare. Weitere Scopes werden nicht mehr durchsucht.
    2. Wähle alle aufrufbaren Funktionen: Schade, keine da.
    3. Keine
    --> Compilerfehler.

    Situation 2 (wie oben, nur CChild überschreibt a nicht):
    1. Die Suche im Scope von CChild ergibt nichts. Also wird der nächst höhere Scope durchsucht. Ergebnis: CBase::a
    2. CBase::a hat eine passende Signatur
    3. CBase::a ist die einzige passende Funktion -> wird also aufgerufen.

    Situation 3 (mit using-Deklaration):
    1. Die Suche in CChild ergibt: CChild::a und CBase::a
    2. Nur CBase::a hat eine passende Signatur
    3. CBase::a ist die einzige passsende Funktion -> wird aufgerufen.

    Situation 4 (mit einer weiteren Methode Child::a(double) und using-Deklaration)
    1. Die Suche in CChild ergibt: 2 x Child::a, CBase::a
    2. CBase::a und CChiild::a(double) sind aufrufbar.
    3. CBase::a ist der "best match", da CChild::a(double) noch eine Promotion int->double erfordern würde. CBase::a hingegen erfordert keine Konvertierung.


Anmelden zum Antworten