Frage

    

Diese Frage bereits eine Antwort hier:

         

In Anbetracht der folgenden Beispiel, warum muss ich ausdrücklich die Aussage b->A::DoSomething() zu verwenden, anstatt nur b->DoSomething()?

Sollte nicht die Überladungsauflösung des Compilers herauszufinden, welche Methode ich rede?

Ich bin mit Microsoft VS 2005. (Anmerkung: virtuelle Anwendung des in diesem Fall nicht helfen)

class A
{
  public:
    int DoSomething() {return 0;};
};

class B : public A
{
  public:
    int DoSomething(int x) {return 1;};
};

int main()
{
  B* b = new B();
  b->A::DoSomething();    //Why this?
  //b->DoSomething();    //Why not this? (Gives compiler error.)
  delete b;
  return 0;
}
War es hilfreich?

Lösung

Die beiden „Überlast“ sind nicht im gleichen Umfang. Standardmäßig hält der Compiler nur den kleinsten möglichen Namensbereich, bis er einen Namen Übereinstimmung findet. Argument Anpassung getan danach . In Ihrem Fall bedeutet dies, dass der Compiler sieht B::DoSomething. Er versucht dann das Argument Liste übereinstimmen, die fehlschlägt.

Eine Lösung wäre, um die Überlastung von A in B Anwendungsbereich nach unten ziehen:

class B : public A {
public:
    using A::DoSomething;
    // …
}

Andere Tipps

Die Überladungsauflösung ist eine der hässlichsten Teile von C ++

Grundsätzlich ist der Compiler findet ein Name match "DoSomething (int)" im Rahmen von B, sieht die Parameter nicht übereinstimmen, und stoppt mit einem Fehler.

Es kann unter Verwendung des A :: DoSomething in der Klasse B überwunden werden

class A  
{  
  public:  
    int DoSomething() {return 0;}
};  

class B : public A  
{  
  public:  
    using A::DoSomething;
    int DoSomething(int x) {return 1;} 
};   


int main(int argc, char** argv)
{
  B* b = new B();  
  // b->A::DoSomething();    // still works, but...
  b->DoSomething();    // works now too
  delete b;  
  return 0;
}

Nein, ist dieses Verhalten vorhanden, um sicherzustellen, dass Sie von den entfernten Basisklassen versehentlich erben werden nicht gefangen werden.

, um es zu erhalten, müssen Sie den Compiler sagen, welche Methode Sie, indem ein mit A :: DoSomething in der B-Klasse aufgerufen werden sollen.

Siehe dieser Artikel für einen schnellen und einfachen Überblick über dieses Verhalten.

Die Anwesenheit eines Verfahren in einer abgeleiteten Klasse blendet alle Methoden mit dem gleichen Namen (unabhängig von Parametern) in Basisklassen. Dies geschieht, um Probleme zu vermeiden wie folgt aus:

class A {} ;
class B :public A
{
    void DoSomething(long) {...}
}

B b;
b.DoSomething(1);     // calls B::DoSomething((long)1));

oder später jemand ändert Klasse A:

class A
{
    void DoSomething(int ) {...}
}

jetzt plötzlich:

B b;
b.DoSomething(1);     // calls A::DoSomething(1);

Mit anderen Worten, wenn es nicht so funktioniert, eine unabhängige Veränderung in einer Klasse, die Sie haben keine Kontrolle (A), könntest still beeinflussen, wie Ihr Code funktioniert.

Das hat etwas mit der Art und Weise der Namensauflösung Werken zu tun. Grundsätzlich finden wir zunächst den Rahmen, aus dem der Name stammt, und dann sammeln wir alle Überlastungen für diesen Namen in diesem Umfang. Allerdings ist der Umfang, in Ihrem Fall der Klasse B und die Klasse B, B :: DoSomething versteckt A :: doSomething:

3.3.7 Namen versteckt [basic.scope.hiding]

... [Ausschnitt] ...

3 In einer Funktionsdefinition, die Deklaration eines lokalen Namen versteckt   die Erklärung eines Mitglieds der Klasse mit dem gleichen Namen; sehen    basic.scope.class . Die Erklärung eines Mitglieds in einer abgeleiteten Klasse   ( class.derived ) verbirgt sich die Erklärung eines Mitglieds einer Basisklasse   der selbe Name; siehe class.member.lookup .

Aufgrund Namen verstecken, A :: DoSomething nicht einmal für die Überladungsauflösung gilt

Wenn Sie eine Funktion in einer abgeleiteten Klasse definieren dann versteckt sie alle Funktionen mit diesem Namen in der Basisklasse. Wenn die Funktion der Basisklasse virtuell ist und eine kompatible Signatur dann die abgeleitete Klasse Funktion überschreibt auch die Funktion der Basisklasse. Sie jedoch, dass nicht die Sicht beeinträchtigen.

können Sie machen die Basisklasse Funktion sichtbar mit einer using-Deklaration:

class B : public A  
{  
  public:  
    int DoSomething(int x) {return 1;};  
    using A::DoSomething;
};  

Das ist nicht zu überlasten! Das ist HIDING!

Wenn der Vererbungsbaumes für die Funktion ohne Argumente die Namen zu verwenden, verwendet C ++ Suche nach oben, sobald es einer Definition gefunden hat es aufhört, dann die Argumente untersucht. In dem gegebenen Beispiel, stoppt er in der Klasse B. Um in der Lage sein, zu tun, was Sie nach, sollte die Klasse B wie folgt definiert werden:

class B : public A  
{  
  public:
    using A::DoSomething;
    int DoSomething(int x) {return 1;};  
}; 

Die Funktion wird durch die Funktion mit dem gleichen Namen in der Unterklasse (aber mit einer anderen Signatur) verborgen ist. Sie können es sichtbar machen, indem die Verwendung von Anweisung, wie Sie sich mit der A :: DoSomething ();

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top