Delegierende Konstruktoren
Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy — Lektion 23 von 104.
Wenn Sie mehrere Konstruktoren haben, die eine gemeinsame Initialisierungslogik teilen, können Sie delegierende Konstruktoren verwenden, um Code-Duplizierung zu vermeiden. Ein delegierender Konstruktor ruft einen anderen Konstruktor derselben Klasse in seiner Initialisierungsliste auf.
class Player {
std::string name;
int health;
int level;
public:
// Primärer Konstruktor - erledigt die eigentliche Arbeit
Player(std::string n, int h, int lvl)
: name(n), health(h), level(lvl) {}
// Delegiert an den primären Konstruktor
Player(std::string n) : Player(n, 100, 1) {}
// Standardkonstruktor delegiert ebenfalls
Player() : Player("Unknown") {}
};Die Delegierung erfolgt in der Initialisierungsliste unter Verwendung des Klassennamens gefolgt von Argumenten. Wenn Player() aufgerufen wird, delegiert er an Player(std::string), welcher dann an den Konstruktor mit drei Parametern delegiert. Die Kette wird vom Zielkonstruktor zurück zum ursprünglichen ausgeführt.
Es gibt eine wichtige Regel: Ein delegierender Konstruktor darf keine weiteren Elemente in seiner Initialisierungsliste haben. Die Delegierung muss das einzige Element sein:
class Item {
int id;
int value;
public:
Item(int i, int v) : id(i), value(v) {}
// Fehler! Delegierung kann nicht mit Elementinitialisierung gemischt werden
// Item(int i) : Item(i, 0), id(i) {}
// Richtig - nur Delegierung
Item(int i) : Item(i, 0) {}
};Delegierende Konstruktoren helfen dabei, die Initialisierungslogik an einem Ort zu zentralisieren, wodurch Ihr Code einfacher zu warten ist und weniger anfällig für Fehler durch duplizierten Code wird.
Aufgabe
EinfachLassen Sie uns ein Verbindungseinstellungssystem erstellen, das zeigt, wie delegierende Konstruktoren Code-Duplizierung eliminieren können, indem sie Konstruktoraufrufe miteinander verketten.
Sie werden zwei Dateien erstellen, um Ihren Code zu organisieren:
Connection.h: Definieren Sie eineConnection-Klasse, die eine Netzwerkverbindung mit verschiedenen Konfigurationsoptionen darstellt. Ihre Klasse sollte Folgendes enthalten:- Private Member:
host(string),port(int),timeout(int in Sekunden) undsecure(bool) - Einen primären Konstruktor, der alle vier Parameter entgegennimmt und alle Member mithilfe einer Initialisierungsliste initialisiert. Dieser Konstruktor sollte
"Connection configured: <host>:<port>"ausgeben. - Einen Konstruktor, der nur
hostundportentgegennimmt und an den primären Konstruktor delegiert, wobeitimeoutstandardmäßig auf30undsecurestandardmäßig auffalsegesetzt wird. - Einen Konstruktor, der nur
hostentgegennimmt und an den Zwei-Parameter-Konstruktor delegiert, wobeiportstandardmäßig auf80gesetzt wird. - Einen Standardkonstruktor, der an den Ein-Parameter-Konstruktor delegiert, wobei
hoststandardmäßig auf"localhost"gesetzt wird. - Eine
getInfo()-Methode, die einen String im Format"<host>:<port> (timeout: <timeout>s, secure: <yes/no>)"zurückgibt.
- Private Member:
main.cpp: Demonstrieren Sie die Delegationskette, indem Sie Verbindungen mit verschiedenen Konstruktoren erstellen. Lesen Sie einen Hostnamen und eine Portnummer von der Eingabe ein (jeweils in einer separaten Zeile) und führen Sie dann Folgendes aus:- Erstellen Sie eine
Connectionmit dem Standardkonstruktor. - Erstellen Sie eine
Connectionnur mit dem Host aus der Eingabe. - Erstellen Sie eine
Connectionmit Host und Port aus der Eingabe. - Erstellen Sie eine
Connectionmit dem eingegebenen Host, dem eingegebenen Port, einem Timeout von60und secure auftruegesetzt. - Geben Sie
getInfo()für jede Verbindung aus, eine pro Zeile.
- Erstellen Sie eine
Die Delegationskette fließt wie folgt: Der Standardkonstruktor ruft den Ein-Parameter-Konstruktor auf, welcher den Zwei-Parameter-Konstruktor aufruft, welcher wiederum den primären Vier-Parameter-Konstruktor aufruft. Das bedeutet, dass die Meldung "Connection configured" für jedes erstellte Objekt einmal ausgegeben wird, und zwar immer vom primären Konstruktor.
Geben Sie für den Sicherheitsstatus in getInfo() "yes" aus, wenn secure true ist, andernfalls "no".
Binden Sie Ihre Header-Datei in main.cpp mit #include "Connection.h" ein.
Spickzettel
Ein delegierender Konstruktor ruft einen anderen Konstruktor derselben Klasse in seiner Initialisierungsliste auf, um Code-Duplizierung zu vermeiden:
class Player {
std::string name;
int health;
int level;
public:
// Primärer Konstruktor
Player(std::string n, int h, int lvl)
: name(n), health(h), level(lvl) {}
// Delegiert an den primären Konstruktor
Player(std::string n) : Player(n, 100, 1) {}
// Standardkonstruktor delegiert ebenfalls
Player() : Player("Unknown") {}
};Die Delegierung erfolgt in der Initialisierungsliste unter Verwendung des Klassennamens gefolgt von Argumenten. Konstruktoren können eine Delegierungskette bilden, bei der einer an einen anderen delegiert.
Wichtige Regel: Ein delegierender Konstruktor darf keine anderen Member in seiner Initialisierungsliste haben. Die Delegierung muss das einzige Element sein:
class Item {
int id;
int value;
public:
Item(int i, int v) : id(i), value(v) {}
// Fehler! Delegierung kann nicht mit Member-Initialisierung gemischt werden
// Item(int i) : Item(i, 0), id(i) {}
// Korrekt - nur Delegierung
Item(int i) : Item(i, 0) {}
};Probier es selbst
#include <iostream>
#include <string>
#include "Connection.h"
using namespace std;
int main() {
// Eingabe lesen
string host;
int port;
cin >> host;
cin >> port;
// TODO: Erstelle eine Connection mit dem Standardkonstruktor
// TODO: Erstelle eine Connection nur mit dem host aus der Eingabe
// TODO: Erstelle eine Connection mit host und port aus der Eingabe
// TODO: Erstelle eine Connection mit host aus der Eingabe, port aus der Eingabe, timeout=60, secure=true
// TODO: Gib getInfo() für jede Verbindung aus, eine pro Zeile
return 0;
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienC++ Build & KompilierungHeader-Dateien & QuelldateienNamensräume & GültigkeitsbereicheEinführung in OOP in C++Klassen vs. ObjekteDer 'this'-PointerMethoden (Elementfunktionen)Attribute (Datenelemente)Grundlagen zu Ctors & DtorsRückblick - Einfacher Taschenrechner4Klasseneigenschaften
Instanz- vs. statische MemberGetter und SetterConst-MemberfunktionenMutable-SchlüsselwortStatische Methoden und VariablenFriend-Funktionen & KlassenZusammenfassung - Bankkonto-Manager7Vererbung
Grundlagen der VererbungZugriffsstufen bei VererbungAufrufreihenfolge von Ctor & DtorÜberschreiben von MethodenVirtuelle Funktionen & VTableMehrfachvererbungVirtuelle VererbungRückblick - Mitarbeiter-Hierarchie2Speicherverwaltung
Stack vs. Heap SpeicherZeiger und ReferenzenDynamischer Speicher (new/delete)Smart Pointers in C++RAII in C++Rückblick – Dynamischer Array-Manager5Kapselung
Zugriffsspezifizierer in C++Zugriffsspezifizierer im DetailInformation HidingStruct vs. ClassVerschachtelte & innere KlassenRückblick - Studentenverwaltungssystem8Polymorphie
Kompilierzeit- vs. Laufzeit-PolymorphieFunktionsüberladungVirtuelle Funktionen – WiederholungRein virtuelle FunktionenAbstrakte KlassenInterface-Design in C++Dynamic Casting & RTTIZusammenfassung – Formen-Rechner3Konstruktoren & Destruktoren
StandardkonstruktorParametrisierter KonstruktorKopierkonstruktorVerschiebekonstruktorKonstruktor-InitialisierungslistenDelegierende KonstruktorenDestruktoren im DetailRule of Three / Five / ZeroZusammenfassung - String-Klasse6Operatorüberladung
Einführung in die OperatorüberladungArithmetische OperatorüberladungVergleichsoperatorüberladungStream-OperatorenZuweisungsoperatorüberladungÜberladen der [] und () OperatorenTypumwandlungsoperatorenRückblick - Matrix-Klasse9Templates
FunktionstemplatesKlassentemplatesTemplate-SpezialisierungVariadische TemplatesSFINAE & Type Traits GrundlagenRückblick - Generische Container