Konstruktor ruft Konstruktor auf: Verkettungen in C++ — ist das möglich?

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

„Von einem Konstruktor zum anderen“: Die ewige Frage eines C++-Entwicklers

\n\n

Stellen Sie sich vor: Sie schreiben eine Klasse mit mehreren Konstruktoren. Einer akzeptiert drei Parameter, ein anderer zwei, ein dritter einen. Und in allen wiederholt sich dieselbe Initialisierungslogik. Die Finger jucken, so etwas wie MyClass() : MyClass(42, "default") {} zu schreiben – und das Duplizieren zu vergessen. Aber der C++-Compiler (bis zu einem bestimmten Punkt) sieht das schief an. Kann man überhaupt einen Konstruktor von einem anderen aus aufrufen? Und wenn ja – wie?

\n\n

Diese Frage ist eine der beliebtesten auf Stack Overflow (Zehntausende von Aufrufen). Kein Wunder: Das Thema Konstruktorverkettung (constructor chaining) ist ein echter Stolperstein für Anfänger und sogar erfahrene Entwickler, die von Java oder Python zu C++ wechseln. In diesem Artikel analysieren wir drei Ansätze zur Lösung des Problems, von „Krücken“ bis hin zu eleganten Lösungen aus C++11, und finden heraus, welcher in echtem Code verwendet werden sollte.

\n\n

Warum kann man nicht einfach einen Konstruktor von einem anderen aus aufrufen?

\n\n

Der naive Ansatz sieht so aus:

\n\n
class MyClass {\npublic:\n    MyClass() {\n        // irgendein Code\n    }\n    MyClass(int x) {\n        MyClass(); // FEHLER: So geht das nicht!\n    }\n};
\n\n

In C++ ist ein Konstruktor keine normale Funktion. Er initialisiert ein Objekt einmal. Wenn Sie versuchen, explizit einen anderen Konstruktor innerhalb des Rumpfes aufzurufen, interpretiert der Compiler dies als Erstellung eines temporären Objekts – und nichts wird in der aktuellen Instanz initialisiert. Das Ergebnis: entweder ein Kompilierungsfehler oder (schlimmer) undefiniertes Verhalten.

\n\n

Vor dem C++11-Standard war die einzige legale Möglichkeit, die Initialisierungslogik zu „teilen“, der Aufruf einer privaten Methode init(). Aber das war keine echte Delegation: Die Klassenmitglieder wurden zuerst vom Standardkonstruktor initialisiert und dann überschrieben. Ineffizient und fehleranfällig.

\n\n

Ansatz Nr. 1: Delegierende Konstruktoren (C++11 und neuer)

\n\n

Ab C++11 gibt es in der Sprache eine lang erwartete Funktion – delegierende Konstruktoren (delegating constructors). Jetzt kann man einen Konstruktor von einem anderen direkt in der Initialisierungsliste aufrufen:

\n\n
class MyClass {\n    int value;\n    std::string name;\npublic:\n    // Basis-Konstruktor\n    MyClass(int v, const std::string& n) : value(v), name(n) {\n        std::cout << "Full init: " << value << ", " << name << "\\n";\n    }\n    // Delegierender Konstruktor\n    MyClass(int v) : MyClass(v, "default") {}\n    // Ein weiterer delegierender\n    MyClass() : MyClass(0, "default") {}\n};
\n\n

Wie funktioniert das? Der Konstruktor MyClass(int v) übergibt die Kontrolle an den Konstruktor MyClass(int, string). Dieser führt die gesamte Initialisierung durch, und erst danach wird die Kontrolle zurückgegeben. Wichtige Regel: In der Initialisierungsliste darf nicht der Aufruf eines anderen Konstruktors mit der direkten Initialisierung von Mitgliedern gemischt werden. Entweder Delegation oder eigene Initialisierung – eines von beiden.

\n\n

Vor- und Nachteile

\n
    \n
  • ✅ Eleganz: Der Code wird sauber, ohne Duplizierung.
  • \n
  • ✅ Leistung: Das Objekt wird einmal initialisiert, ohne unnötige Operationen.
  • \n
  • ⚠️ Einschränkung: Delegation funktioniert nur in einer „Tiefe“ – die Kette kann nicht rekursiv sein (Sie verursachen einen Stack-Überlauf).
  • \n
  • ⚠️ Kompatibilität: Erfordert C++11 oder neuer. Wenn Sie an einem alten Compiler hängen – diese Option ist nichts für Sie.
  • \n
\n\n

Ansatz Nr. 2: Private Methode init()

\n\n

Die klassische „Vor-C++11“-Methode – die gemeinsame Logik in eine private Methode auslagern. Sieht so aus:

\n\n
class MyClass {\n    int value;\n    std::string name;\n    void init(int v, const std::string& n) {\n        value = v;\n        name = n;\n        std::cout << "Init called\\n";\n                

Blogs

Buchempfehlungen