Konstruktor Verwirrung

8

Ich denke immer, dass ich C ++ ziemlich gut kenne, aber manchmal bin ich sogar von den grundlegendsten Dingen überrascht.

Im folgenden Szenario bin ich verwirrt, warum der Konstruktor Derived::Derived(const Base&) aufgerufen wird:

%Vor%

Dies gibt aus: Called Derived::Derived(const Base& b) , was anzeigt, dass der zweite Konstruktor in Derived aufgerufen wurde. Jetzt dachte ich, dass ich C ++ ziemlich gut kannte, aber ich kann nicht herausfinden, warum dieser Konstruktor aufgerufen würde. Ich verstehe das ganze "Viererregel" -Konzept, und ich würde denken, dass der Ausdruck d = b eines von zwei Dingen tun würde: Entweder es würde 1) den impliziten (Compiler-generierten) Zuweisungsoperator von Base oder 2 aufrufen ) Leiten Sie einen Compilerfehler ein, indem Sie sich beschweren, dass die Funktion Derived& operator = (const Base&) nicht existiert.

Stattdessen wurde ein -Konstruktor aufgerufen, obwohl der Ausdruck d = b ein Zuweisungsausdruck ist.

Warum passiert das?

    
Channel72 28.05.2011, 17:31
quelle

5 Antworten

11

d = b kann passieren, weil b in abgeleitet wird. Der zweite Konstruktor wird für die automatische Typkonvertierung verwendet. Es ist wie d = (abgeleitet) b

Abgeleitete isa-Basis, aber Basis ist nicht abgeleitet, daher muss sie vor der Zuweisung konvertiert werden.

    
George Kastrinis 28.05.2011, 17:35
quelle
6

Zuordnung der Basis zu abgeleitet? vielleicht meintest du (a) mit ref (b) oder abgeleitet von basis. Das ist nicht wirklich sinnvoll, aber der Compiler verwendet Ihren (nicht expliziten) Konstruktor korrekt, um die Base-Instanz in eine neue Derived-Instanz zu konvertieren (die anschließend in d zugewiesen wird).

Verwenden Sie einen Explicut-Konstruktor, um dies automatisch zu verhindern.

Ich persönlich denke, Sie haben Ihr Codebeispiel durcheinander gebracht, weil die Zuweisung der ersten Klasse zu abgeleiteten Klassen ohne eine Konvertierung keinen Sinn ergibt.

    
sehe 28.05.2011 17:37
quelle
5

Hier spielen zwei interagierende Features eine Rolle:

  • Zuweisungsoperatoren werden niemals vererbt
  • Ein Konstruktor, der nicht explizit ist, oder ein Konvertierungsoperator ( operator T() ) definieren eine Benutzerkonvertierung, die implizit als Teil einer Konvertierungssequenz
  • verwendet werden kann

Zuweisungsoperatoren werden niemals vererbt

Ein einfaches Codebeispiel:

%Vor%

Von ideone :

%Vor%

Konvertierungssequenz

Immer wenn eine "Impedanz" nicht übereinstimmt, wie hier:

  • Derived::operator= erwartet ein Derived const& Argument
  • a Base& wird bereitgestellt

Der Compiler wird versuchen, eine Konvertierungssequenz zu erstellen, um die Lücke zu überbrücken. Eine solche Konvertierungssequenz kann bei am meisten eine benutzerdefinierte Konvertierung enthalten.

Hier wird gesucht:

  • jeder Konstruktor von Derived , der mit einem Base& (nicht explizit)
  • aufgerufen werden kann
  • ein Konvertierungsoperator in Base , der ein Derived -Element
  • ergibt

Es gibt keine Base::operator Derived() , aber es gibt einen Derived::Derived(Base const&) -Konstruktor.

Daher ist unsere Konvertierungssequenz für uns definiert:

  • Base&
  • Base const& (trivial)
  • Derived (mit Derived::Derived(Base const&) )
  • Derived const& (temporäres Objekt, das an eine const-Referenz gebunden ist)

Und dann wird Derived::operator(Derived const&) aufgerufen.

In Aktion

Wenn wir den Code mit weiteren Spuren ergänzen, können wir es in Aktion sehen .

%Vor%

Welche Ausgaben:

%Vor%

Hinweis: Dies verhindern?

In C ++ ist es möglich, einen Konstruktor für die Verwendung in Konvertierungssequenzen zu entfernen. Dazu muss die Deklaration des Konstruktors mit dem Schlüsselwort explicit vorangestellt werden.

In C ++ 0x wird es möglich, dieses Schlüsselwort auch für Konvertierungsoperatoren ( operator T() ) zu verwenden.

Wenn wir explicit vor Derived::Derived(Base const&) verwenden, wird der Code schlecht formatiert und sollte vom Compiler abgelehnt werden.

    
Matthieu M. 28.05.2011 18:06
quelle
2

Da Sie einen Konstruktor für Derived definiert haben, der den Typ Base akzeptiert und Sie Base down-Casting ausführen, wählt der Compiler den passendsten Konstruktor für den Upcast aus, in diesem Fall den Dervied (const Base & amp; b) you ' definiert werden. Wenn Sie diesen Konstruktor nicht definieren, erhalten Sie tatsächlich einen Kompilierungsfehler, wenn Sie versuchen, die Zuweisung vorzunehmen. Weitere Informationen finden Sie unter Linuxtopia .

    
Hazok 28.05.2011 17:42
quelle
1

Es kann keinen anderen Wert zuweisen, daher sollte zuerst ein Derived temporary erstellt werden.

    
Michael Krelin - hacker 28.05.2011 17:37
quelle

Tags und Links