Menu
Coddy logo textTech

Konstruktor-Initialisierungslisten

Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy — Lektion 22 von 104.

Sie haben die Doppelpunkt-Syntax in vorherigen Lektionen gesehen, wie zum Beispiel Player(std::string n, int h) : name(n), health(h) {}. Dies wird als Elementinitialisierungsliste bezeichnet und ist die bevorzugte Methode, um Member in C++ zu initialisieren.

Die Initialisierungsliste erscheint nach der Parameterliste des Konstruktors, beginnend mit einem Doppelpunkt. Jedes Mitglied wird direkt mit seinem Wert initialisiert, getrennt durch Kommas:

class Rectangle {
    int width;
    int height;
    const int id;
    int& reference;
public:
    Rectangle(int w, int h, int i, int& r) 
        : width(w), height(h), id(i), reference(r) {
        // Konstruktor-Rumpf (kann leer sein)
    }
};

Warum sollte man Initialisierungslisten anstelle von Zuweisungen im Konstruktorrumpf verwenden? Bei der Zuweisung werden Member zuerst standardmäßig konstruiert und anschließend werden ihnen neue Werte zugewiesen. Mit Initialisierungslisten werden Member direkt mit den korrekten Werten konstruiert – das ist effizienter und in manchen Fällen zwingend erforderlich.

Bestimmte Member müssen über die Liste initialisiert werden:

  • const-Member – können nach der Konstruktion nicht mehr zugewiesen werden
  • Referenz-Member – müssen bei der Initialisierung gebunden werden
  • Member ohne Standardkonstruktoren
class Player {
    const int maxHealth;    // Muss Initialisierungsliste verwenden
    std::string name;
public:
    // Das funktioniert
    Player(int max, std::string n) : maxHealth(max), name(n) {}
    
    // Dies würde NICHT kompilieren:
    // Player(int max) { maxHealth = max; }  // Fehler!
};

Elemente werden in der Reihenfolge initialisiert, in der sie in der Klasse deklariert sind, nicht in der Reihenfolge in der Initialisierungsliste. Schreiben Sie Ihre Initialisierungsliste immer in der Deklarationsreihenfolge, um Verwirrung zu vermeiden.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein Konfigurationssystem für eine Game-Engine erstellen, das demonstriert, wann und warum Elementinitialisierungslisten (Member Initializer Lists) unerlässlich sind. Sie werden eine GameConfig-Klasse mit Elementen erstellen, die mithilfe der Initialisierungslisten-Syntax initialisiert werden müssen.

Sie werden zwei Dateien erstellen, um Ihren Code zu organisieren:

  • GameConfig.h: Definieren Sie eine GameConfig-Klasse, die Spieleinstellungen speichert. Ihre Klasse sollte Folgendes enthalten:
    • Ein const std::string gameName — der Titel des Spiels, der sich nach der Erstellung nicht mehr ändern kann
    • Ein const int maxPlayers — die maximale Spieleranzahl, die bei der Konstruktion festgelegt wird
    • Ein int& difficultyRef — eine Referenz auf eine externe Schwierigkeitseinstellung
    • Ein int screenWidth und int screenHeight — reguläre Elemente für Anzeigeeinstellungen
    • Einen Konstruktor, der alle notwendigen Parameter entgegennimmt und jedes Element mithilfe der Initialisierungsliste initialisiert. Die Initialisierungsliste sollte der Reihenfolge folgen, in der die Elemente in der Klasse deklariert sind
    • Eine display()-Methode, welche die Konfiguration in diesem Format ausgibt:
      Game: <gameName>
      Max Players: <maxPlayers>
      Difficulty: <difficultyRef value>
      Resolution: <screenWidth>x<screenHeight>
  • main.cpp: Lesen Sie Konfigurationswerte aus der Eingabe ein und erstellen Sie ein GameConfig-Objekt. Sie müssen:
    • Den Spielnamen (string), die maximale Spieleranzahl (int), die Schwierigkeit (int), die Breite (int) und die Höhe (int) aus der Eingabe lesen — jeweils in einer separaten Zeile
    • Eine lokale int-Variable für die Schwierigkeit erstellen, auf die die Konfiguration verweisen wird
    • Ein GameConfig-Objekt unter Verwendung des Initialisierungslisten-Konstruktors erstellen
    • display() aufrufen, um die initiale Konfiguration anzuzeigen
    • Die Schwierigkeitsvariable direkt ändern (mit 2 multiplizieren)
    • "After difficulty change:" ausgeben
    • display() erneut aufrufen, um zu zeigen, dass die Referenz den aktualisierten Wert widerspiegelt

Diese Herausforderung verdeutlicht, warum Initialisierungslisten wichtig sind: Ihre const-Elemente und das Referenz-Element können nicht im Konstruktorrumpf zugewiesen werden — sie müssen in der Liste initialisiert werden. Das Referenz-Element zeigt zudem, wie Änderungen an der ursprünglichen Variable durch das Konfigurationsobjekt reflektiert werden.

Binden Sie Ihre Header-Datei in main.cpp mit #include "GameConfig.h" ein.

Spickzettel

Eine Elementinitialisierungsliste ist die bevorzugte Art, Klassen-Member in C++ zu initialisieren. Sie erscheint nach der Parameterliste des Konstruktors, beginnt mit einem Doppelpunkt, wobei jedes Member direkt initialisiert wird:

class Rectangle {
    int width;
    int height;
public:
    Rectangle(int w, int h) : width(w), height(h) {
        // Konstruktor-Rumpf
    }
};

Warum Initialisierungslisten verwenden? Member werden direkt mit den korrekten Werten konstruiert, anstatt standardmäßig konstruiert und anschließend zugewiesen zu werden, was effizienter ist.

Erforderlich für bestimmte Member:

  • const-Member - können nach der Konstruktion nicht mehr zugewiesen werden
  • Referenz-Member - müssen bei der Initialisierung gebunden werden
  • Member ohne Standardkonstruktoren
class Player {
    const int maxHealth;
    int& reference;
public:
    // Korrekt - verwendet Initialisierungsliste
    Player(int max, int& r) : maxHealth(max), reference(r) {}
    
    // Fehler - const oder Referenz kann nicht im Rumpf zugewiesen werden
    // Player(int max) { maxHealth = max; }
};

Wichtig: Member werden in der Reihenfolge initialisiert, in der sie in der Klasse deklariert sind, nicht in der Reihenfolge in der Initialisierungsliste. Schreiben Sie Ihre Initialisierungsliste immer in der Deklarationsreihenfolge.

Probier es selbst

#include <iostream>
#include <string>
#include "GameConfig.h"

using namespace std;

int main() {
    // Eingabewerte lesen
    string gameName;
    getline(cin, gameName);
    
    int maxPlayers;
    cin >> maxPlayers;
    
    int difficulty;
    cin >> difficulty;
    
    int width;
    cin >> width;
    
    int height;
    cin >> height;
    
    // TODO: Erstelle ein GameConfig-Objekt unter Verwendung des Initialisierungslisten-Konstruktors
    // Der Konstruktor sollte empfangen: gameName, maxPlayers, difficulty (per Referenz), width, height
    
    // TODO: Rufe display() auf, um die ursprüngliche Konfiguration anzuzeigen
    
    // TODO: Ändere die Variable difficulty direkt (multipliziere sie mit 2)
    
    // TODO: Gib "After difficulty change:" aus
    
    // TODO: Rufe display() erneut auf, um die aktualisierte Konfiguration anzuzeigen
    
    return 0;
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung