2010-11-24 10 views
1

Lassen Sie das Beispiel sein:Basisklasse auf der Initialisierungsliste einer abgeleiteten Klasse Copy-Konstruktor (C++)

class Base { 
    Base (const Base & copyFrom) { globalRegister (* this); } 
} 

class Derived { 
    Derived (const Derived & copyFrom) : Base (copyFrom) {} 
} 

ich Vorschläge gelesen habe die Basis des Copykonstruktor auf der Initialisierung Liste aufzunehmen von um Abgeleitet um die Eigenschaften der Base zu kopieren (wie im Beispiel).

Allerdings habe ich den Copy-Konstruktor der Base, der sich selbst (* this) an ein anderes Objekt übergibt (um mit diesem Objekt registriert zu werden). Wäre das ein Fall, in dem ich (implizit oder explizit) den Konstruktor von Base (Standard) in der Initialisierungsliste des Kopierkonstruktors von Derived benutzen und den Kopierkonstruktor der Base nur im Rumpf des Kopierkonstruktors von Derived aufrufen muss, wenn es tatsächlich ein Objekt gibt das kann von Base's Kopierkonstruktor angehängt werden? Else - ist (* das) ein gültiges Objekt?

+0

Sie übergeben '* this' nicht aus' Base's Initialisierungsliste, richtig? –

+0

@ John Dibling: Nein, es ist im Körper von Base's Kopierkonstruktor. –

Antwort

4

Wäre das der Fall sein, wo ich muß tatsächlich nutzen (implizit oder explizit) Basis der (Standard) Konstruktor auf der Initialisierung Liste des Copy-Konstruktor der abgeleiteten und rufen Sie die Kopie Konstruktor der Basis nur im Körper des Copykonstruktor des Abgeleitet wenn es tatsächlich ein Objekt gibt, das mit dem Kopierkonstruktor von Base verbunden werden kann?

Warum in aller Welt möchten Sie das tun?
(Oh, und Sie können eine Basisklasse Copy-Konstruktor von einer abgeleiteten Klasse nicht nennen Konstruktor Körper Nur aus seiner Initialisierungsliste..)

andere - ist (* this) ein gültiges Objekt?

Sobald die Initialisierungsliste der Basis abgeschlossen ist, sind alle Basiselemente (und Basisklassen) vollständig aufgebaut. Die Klasse selbst ist jedoch erst vollständig konstruiert, wenn ihr Konstruktor fertig ist.
Noch wichtiger ist, dass der Konstruktor der abgeleiteten Klasse noch nicht einmal gestartet wurde, also ist das Objekt noch kein Objekt einer abgeleiteten Klasse.

Also was auch immer diese Registrierungsfunktion tut, muss berücksichtigt werden, dass der dynamische Typ des Objekts base ist und dass sein Konstruktor noch nicht fertig ist. (Um sicher zu sein, alles was man tun kann, ist, die irgendwo Adresse des Objekts zu speichern.)

+0

> Warum in aller Welt möchten Sie das tun?

+0

@ Janis: Aber Sie _are _ nennen den Kopierkonstruktor der Basisklasse - von der Initialisierungsliste, die genau dort ist, wo Sie das tun sollen. Warum sollten Sie stattdessen den Standardkonstruktor aufrufen? – sbi

+0

Das war genau das, was ich bezweifelte - ob ich es aus der Initialisierungsliste oder aus dem Körper des Konstruktors des Derived (wie Sie mir jetzt gesagt haben, ist sowieso unmöglich). Da ich dachte, dass der copy-constructor der Base, wenn er aus der Initialisierungsliste aufgerufen würde, nicht in der Lage wäre, (* this) zu verwenden, während er vom Body aus aufgerufen werden könnte (um zu einer anderen Funktion zu gelangen). Wenn (* dieses) Objekt bereits verfügbar ist, ist es in Ordnung. Ich muss nur sicherstellen, dass es nur das verwendet, was in der Basisklasse verfügbar ist, da nur der abgeleitete Teil noch nicht verfügbar ist. –

1

Gerade als Referenz wird das Verhalten spezifiziert durch § 12.7 2-3 von C++ 03:

2) Um explizit oder implizit einen Zeiger (einen L-Wert) zu referenzieren, der sich auf ein Objekt der Klasse X bezieht, auf einen Zeiger (Verweis) auf eine direkte oder indirekte Basisklasse B von X, die Konstruktion von X und die Konstruktion aller seiner direkten oder indirekten Basen die direkt oder indirekt von B herrühren, müssen begonnen haben und die Zerstörung dieser Klassen darf nicht abgeschlossen sein, andernfalls führt die Umwandlung zu undefiniertem Verhalten.

this ist ein Zeiger auf Derived. In Base::Base(), this wird implizit in eine Base* umgewandelt, die erlaubt ist, weil die Konstruktion von Derived begonnen hat und es keine anderen Basen hat, die von Base abgeleitet sind.

§ 12.7 2 weiter:

Um eine direkte nicht-statische Element eines Objekts obj, den Bau von obj einen Zeiger auf (den Wert oder Access) zu bilden begonnen haben soll und dessen Zerstörung wird nicht vollendet haben, andernfalls die Berechnung von Der Pointer-Wert (oder Zugriff auf den Member-Wert) führt zu undefiniertem Verhalten.

Schließlich § 12.7 3 ist auch wichtig:

3) Mitgliedfunktionen, einschließlich virtuellen Funktionen (10.3), können während der Konstruktion oder Zerstörung (12.6.2) aufgerufen werden. Wenn eine virtuelle Funktion direkt oder indirekt von einem Konstruktor aufgerufen wird (einschließlich aus dem mem-initializer für ein Datenelement) oder von einem Destruktor und das Objekt, auf das der Aufruf angewendet wird, das Objekt im Bau oder die Zerstörung aufgerufen wird ist diejenige, die in der eigenen Klasse des Konstruktors oder des Destruktors oder in einer seiner Basen definiert ist, aber keine Funktion, die in einer von der Klasse des Konstruktors oder Destruktors abgeleiteten Klasse überschrieben oder in einer der anderen Basisklassen überschrieben wird abgeleitetes Objekt (1.8). Wenn der Aufruf der virtuellen Funktion einen expliziten Klassenmemberzugriff (5.2.5) verwendet und sich der Objektausdruck auf das Objekt in Konstruktion oder Zerstörung bezieht, aber sein Typ weder die eigene Klasse des Konstruktors oder des Destruktors noch eine seiner Basen ist, ist das Ergebnis von Anruf ist nicht definiert.

Diese beiden Klauseln bedeutet eine Instanz von Derived ein vollwertiges ist Base einmal Base Konstruktor beginnt, obwohl es in einem inkonsistenten Zustand sein könnte.