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
EinfachErstelle ein Verbindungseinstellungssystem, das zeigt, wie delegierende Konstruktoren durch das Verketten von Konstruktoraufrufen Code-Duplikation vermeiden können.
Du erstellst zwei Dateien, um deinen Code zu organisieren:
Connection.h: Definiere eineConnection-Klasse, die eine Netzwerkverbindung mit verschiedenen Konfigurationsoptionen darstellt. Deine 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 Konstruktor mit zwei Parametern delegiert, wobeiportstandardmäßig auf80gesetzt wird - Einen Standardkonstruktor, der an den Konstruktor mit einem Parameter delegiert, wobei
hoststandardmäßig auf"localhost"gesetzt wird - Eine
getInfo()-Methode, die einen String im folgenden Format zurückgibt:"<host>:<port> (timeout: <timeout>s, secure: <yes/no>)"
- Private Member:
main.cpp: Zeige die Delegationskette, indem du Verbindungen mithilfe verschiedener Konstruktoren erstellst. Lies einen Hostnamen und eine Portnummer aus der Eingabe ein (jeweils in einer eigenen Zeile), und:- Erstelle eine
Connectionmithilfe des Standardkonstruktors - Erstelle eine
Connectionnur mit dem Host aus der Eingabe - Erstelle eine
Connectionmit Host und Port aus der Eingabe - Erstelle eine
Connectionmit dem eingegebenen Host, dem eingegebenen Port, einem Timeout von60und auftruegesetztem secure-Status - Gib für jede Verbindung
getInfo()aus, jeweils eine Ausgabe pro Zeile
- Erstelle eine
Die Delegationskette verläuft folgendermaßen: Der Standardkonstruktor ruft den Konstruktor mit einem Parameter auf, dieser ruft den Konstruktor mit zwei Parametern auf, und dieser ruft den primären Konstruktor mit vier Parametern auf. Das bedeutet, dass die Meldung "Connection configured" für jedes erstellte Objekt einmal ausgegeben wird, und zwar immer aus dem primären Konstruktor.
Gib für den secure-Status in getInfo() "yes" aus, wenn secure den Wert true hat, andernfalls "no".
Binde deine Header-Datei in main.cpp mithilfe von #include "Connection.h" ein.
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 & QuelldateienNamespaces & GültigkeitsbereichEinführung in OOP mit C++Klassen vs. ObjekteDer „this“-ZeigerMethoden (Member-Funktionen)Attribute (Datenmember)Grundlagen zu Ctors & DtorsRückblick – Einfacher Taschenrechner4Klassenattribute
Instanz- vs. statische MemberGetter und SetterConst-MemberfunktionenMutable-SchlüsselwortStatische Methoden und VariablenFriend-Funktionen und -KlassenZusammenfassung – Bankkontoverwaltung7Vererbung
Grundlagen der VererbungZugriffsebenen bei der VererbungAufrufreihenfolge von Ctor & DtorÜberschreiben von MethodenVirtuelle Funktionen & VTableMehrfachvererbungVirtuelle VererbungRückblick – Mitarbeiterhierarchie2Speicherverwaltung
Stack- vs. Heap-SpeicherZeiger und ReferenzenDynamischer Speicher (new/delete)Intelligente Zeiger in C++RAII in C++Rückblick – Dynamischer Array-Manager5Kapselung
Zugriffsbezeichner in C++Zugriffsbezeichner im DetailInformationsverbergungStruct vs. KlasseVerschachtelte und innere KlassenWiederholung – Studierendenverwaltungssystem8Polymorphie
Polymorphie zur Compilezeit vs. LaufzeitFunktionsüberladungVirtuelle Funktionen erneut betrachtetRein virtuelle FunktionenAbstrakte KlassenInterface-Design in C++Dynamic Casting & RTTIRückblick – Shape-Calculator3Konstruktoren & Destruktoren
StandardkonstruktorParametrisierter KonstruktorKopierkonstruktorMove-KonstruktorKonstruktor-InitialisierungslistenDelegierende KonstruktorenDestruktor im DetailDrei-/Fünf-/Null-RegelZusammenfassung – String-Klasse6Operatorüberladung
Einführung in die OperatorüberladungArithmetische OperatorüberladungVergleichsoperatorüberladungStream-OperatorenZuweisungsoperatorüberladungÜberladung der Operatoren [] und ()TypkonvertierungsoperatorenWiederholung – Matrix-Klasse9Templates
FunktionstemplatesKlassen-TemplatesTemplate-SpezialisierungVariadische TemplatesGrundlagen zu SFINAE und Type TraitsRückblick – Generischer ContainerÜbe selbstständig: Online-C++-Compiler