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:
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?
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.
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.
Hier spielen zwei interagierende Features eine Rolle:
operator T()
) definieren eine Benutzerkonvertierung, die implizit als Teil einer Konvertierungssequenz 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 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:
Derived
, der mit einem Base&
(nicht explizit) Base
, der ein Derived
-Element 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.
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 .
Es kann keinen anderen Wert zuweisen, daher sollte zuerst ein Derived
temporary erstellt werden.
Tags und Links c++ constructor