1. Problembeschreibung
Im Vererbungssystem muss eine abgeleitete Klasse, wenn sie den Konstruktor der Basisklasse verwenden möchte, ihn im Konstruktor explizit deklarieren.
Wie folgt:
Hier ist B von A abgeleitet, und B
ruft auch in seinem Konstruktor den Konstruktor von A auf, wodurch die Weitergabe des Konstruktors vollendet wird.
Ein weiteres Beispiel ist wie folgt. Wenn B Mitgliedsvariablen enthält:
Nun enthält das von A abgeleitete struct B eine Mitgliedsvariable. Wir initialisieren das Mitglied d gleichzeitig mit der Initialisierung der Basisklasse A. Das Problem ist nun: Wenn die Basisklasse zahlreiche Konstruktoren mit unterschiedlichen Versionen hat, dann müssen wir in der abgeleiteten Klasse nach dem obigen Ansatz weiterhin viele entsprechende "Weiterleitungs"-Konstruktoren schreiben. Zum Beispiel:
Offensichtlich wird das Schreiben des Konstruktors der abgeleiteten Klasse sehr umständlich und recht unbequem, wenn die Basisklasse viele Konstruktoren hat.
2. Lösung des Problems
Wir können dieses Problem durch eine using-Deklaration vereinfachen. Betrachten wir ein Beispiel.
In dem Code deklarieren sowohl die Basisklasse als auch die abgeleitete Klasse eine Funktion f mit demselben Namen. Aber die Methode in der abgeleiteten Klasse unterscheidet sich von der Version der Basisklasse. Hier wird eine using-Deklaration verwendet, um anzugeben, dass die abgeleitete Klasse auch die Version der Funktion f aus der Basisklasse verwendet. Auf diese Weise hat die abgeleitete Klasse zwei Versionen der Funktion f. Was hier erklärt werden muss, ist: Wenn keine using-Deklaration verwendet wird, um die gleichnamige Funktion der Elternklasse zu erben, dann verbirgt die in der abgeleiteten Klasse definierte Funktion f die Funktion f der Elternklasse. Wenn die abgeleitete Klasse diese gleichnamige Funktion f überhaupt nicht definiert, wählt sie natürlich trotzdem die Funktion f der Basisklasse.
Wir können diese Methode auch auf die Vererbung von Konstruktoren anwenden. Das heißt, die abgeleitete Klasse kann mit einer using-Anweisung deklarieren, dass sie alle Konstruktoren der Basisklasse in der Unterklasse erbt. Zum Beispiel:
Nun werden durch die using A::A-Deklaration alle Konstruktoren der Basisklasse in die abgeleitete Klasse geerbt. Noch raffinierter ist, dass dies eine implizit deklarierte Vererbung ist. Das heißt, wenn ein geerbter Konstruktor vom relevanten Code nicht verwendet wird, erzeugt der Compiler keinen tatsächlichen Funktionscode dafür, was mehr Zielcode-Speicherplatz spart als die Durchleitungsweiterleitung der verschiedenen Basisklassen-Konstruktoren. Aber an diesem Punkt gibt es noch ein weiteres Problem:
Wenn man die using-Anweisung verwendet, um Basisklassen-Konstruktoren zu erben, kann die abgeleitete Klasse neue Klassenmember, die von der Klasse selbst definiert werden, nicht initialisieren. Wir können Klassenmember-Initialisierungsausdrücke verwenden, um Standardinitialwerte für Member der abgeleiteten Klasse festzulegen. Zum Beispiel:
Hinweis:
1. Bei geerbten Konstruktoren werden die Standardwerte der Parameter nicht geerbt. Darüber hinaus führen Standardwerte dazu, dass die Basisklasse mehrere Konstruktorversionen erzeugt (das heißt, Parameter werden von hinten nach vorne entfernt, bis der Konstruktor ohne Argumente enthalten ist; natürlich, wenn es sich um einen Standard-Kopierkonstruktor handelt, ist dieser ebenfalls enthalten). All diese Konstruktorversionen werden von der abgeleiteten Klasse geerbt.
2. Konfliktbehandlung bei geerbten Konstruktoren: Wenn eine abgeleitete Klasse mehrere Basisklassen hat, können einige Konstruktoren unter den mehreren Basisklassen dazu führen, dass die Funktionsnamen der geerbten Konstruktoren in der abgeleiteten Klasse gleich sind.
Wenn die Parameter ebenfalls gleich sind, dann führen die geerbten Konstruktoren in der abgeleiteten Klasse zu illegalem Code der abgeleiteten Klasse. Zum Beispiel:
Hier werden die geerbten Konstruktoren in der abgeleiteten Klasse in Konflikt geraten. Eine Lösung besteht darin, die in Konflikt stehenden Konstruktoren der Klasse explizit zu erben, wodurch die implizite Erzeugung der entsprechenden geerbten Konstruktoren verhindert wird, um Konflikte zu vermeiden.
3. Wenn der Konstruktor der Basisklasse als privater Konstruktor deklariert ist oder die abgeleitete Klasse virtuell von der Basisklasse erbt, dann können geerbte Konstruktoren nicht in der abgeleiteten Klasse deklariert werden.
4. Wenn geerbte Konstruktoren verwendet werden, generiert der Compiler keinen Standardkonstruktor für die abgeleitete Klasse. Daher müssen wir darauf achten, ob die argumentlose Version des geerbten Konstruktors erforderlich ist.
Quelle: http://www.cnblogs.com/yangykaifa/p/6737354.html