Geschichte der Frage:
In klassischem C++ wurden Klassenmitglieder nur in der Initialisierungsliste des Konstruktors initialisiert. Mit C++11 wurde die Möglichkeit eingeführt, Standardwerte direkt in der Deklaration innerhalb der Klasse anzugeben (Member-Initialisierer), um die Lesbarkeit und Sicherheit des Codes zu erhöhen.
Problem:
Es gibt mehrere Möglichkeiten, einem Klassenmitglied einen Wert zuzuweisen: direkt in der Deklaration (in-class), über die Initialisierungsliste des Konstruktors und im Körper des Konstruktors. Verschiedene Methoden beeinflussen die Leistung und Semantik; ein falsches Verständnis führt zu unnötiger Kopie oder Standarddestruktoren, sowie zu Fehlern bei Konstanten und Referenzen.
Lösung:
class MyClass { int x = 42; };
class MyClass { const int y; MyClass(int val) : y(val) {} // sonst — Kompilierungsfehler };
class MyClass { std::string s; MyClass() { s = "hello"; } // Zuerst Standard, dann Zuweisung };
Wesentliche Merkmale:
Wie sieht die Reihenfolge der Initialisierung von Mitgliedern aus: in der Reihenfolge, in der sie in der Klasse deklariert sind, oder in der Reihenfolge der Initialisierungsliste?
Die Reihenfolge der Initialisierung ist immer die, in der die Mitglieder in der Klasse deklariert sind, und nicht in der Reihenfolge der Initialisierungsliste. Eine Verletzung der Reihenfolge ist gefährlich für abhängige Mitglieder.
class A { int x = 1; int y = 2; A() : y(10), x(20) {} }; // x wird vor y initialisiert, trotz der Reihenfolge in der Liste
Kann ein Mitgliedskonstanten im Körper des Konstruktors initialisiert werden, wenn es nicht in der Liste initialisiert wurde?
Nein. Konstanten werden nur in der Initialisierungsliste initialisiert. Eine Zuweisung im Körper des Konstruktors führt zu einem Kompilierungsfehler.
Was passiert, wenn ein Standardwert für ein Mitglied direkt in der Klasse über einen In-Class-Initialisierer angegeben wird und er in der Initialisierungsliste des Konstruktors überschrieben wird?
Der Wert aus der Initialisierungsliste des Konstruktors wird verwendet. Der Standardwert wird nur verwendet, wenn die Liste nichts angibt.
class C { int x = 10; C() : x(20) {} // x wird gleich 20 sein };
Die Klasse arbeitet mit einer Datei. Die Datei wird als std::ofstream deklariert und im Körper des Konstruktors initialisiert. Gefahr: Mit dem Standardkonstruktor kann ein ungültiges std::ofstream erstellt werden, was zu Fehlern beim Arbeiten mit der Datei führt.
Vorteile:
Nachteile:
Die Datei wird in der Initialisierungsliste initialisiert, was die fehlerhafte Verwendung der Datei mit ungültigem Zustand blockiert, während Mitglieder mit Standarddaten einen In-Class-Initialisierer verwenden.
Vorteile:
Nachteile: