Konstruktory delegujące
Część sekcji Programowanie obiektowe ścieżki C++ w Coddy. Lekcja 23 z 104.
Gdy masz wiele konstruktorów współdzielących wspólną logikę inicjalizacji, możesz użyć konstruktorów delegujących, aby uniknąć powielania kodu. Konstruktor delegujący wywołuje inny konstruktor tej samej klasy na swojej liście inicjalizacyjnej.
class Player {
std::string name;
int health;
int level;
public:
// Konstruktor główny – wykonuje właściwą pracę
Player(std::string n, int h, int lvl)
: name(n), health(h), level(lvl) {}
// Deleguje do konstruktora głównego
Player(std::string n) : Player(n, 100, 1) {}
// Konstruktor domyślny również deleguje
Player() : Player("Unknown") {}
};Delegowanie odbywa się na liście inicjalizacyjnej za pomocą nazwy klasy, po której następują argumenty. Gdy wywoływane jest Player(), deleguje ono do Player(std::string), które następnie deleguje do konstruktora z trzema parametrami. Łańcuch wykonuje się od konstruktora docelowego z powrotem do pierwotnego.
Jest jedna ważna zasada: konstruktor delegujący nie może mieć innych elementów na liście inicjalizacyjnej. Delegowanie musi być jedynym elementem:
class Item {
int id;
int value;
public:
Item(int i, int v) : id(i), value(v) {}
// Błąd! Nie można łączyć delegowania z inicjalizacją pól klasy
// Item(int i) : Item(i, 0), id(i) {}
// Poprawnie – tylko delegowanie
Item(int i) : Item(i, 0) {}
};Konstruktory delegujące pomagają scentralizować logikę inicjalizacji w jednym miejscu, dzięki czemu kod jest łatwiejszy w utrzymaniu i mniej podatny na błędy wynikające z powielania kodu.
Wyzwanie
ŁatwyUtwórzmy system ustawień połączenia, który pokazuje, jak konstruktory delegujące mogą wyeliminować powielanie kodu przez łańcuchowe wywoływanie konstruktorów.
Utworzysz dwa pliki, aby uporządkować kod:
Connection.h: Zdefiniuj klasęConnection, która reprezentuje połączenie sieciowe z różnymi opcjami konfiguracji. Twoja klasa powinna zawierać:- Prywatne składowe:
host(string),port(int),timeout(int w sekundach) isecure(bool) - Konstruktor główny, który przyjmuje wszystkie cztery parametry i inicjalizuje wszystkie składowe za pomocą listy inicjalizacyjnej. Ten konstruktor powinien wypisać
"Connection configured: <host>:<port>" - Konstruktor przyjmujący tylko
hostiport, który deleguje do konstruktora głównego, domyślnie ustawiająctimeoutna30isecurenafalse - Konstruktor przyjmujący tylko
host, który deleguje do konstruktora dwuparametrowego, domyślnie ustawiającportna80 - Konstruktor domyślny, który deleguje do konstruktora jednoargumentowego, domyślnie ustawiając
hostna"localhost" - Metodę
getInfo(), która zwraca ciąg znaków w formacie:"<host>:<port> (timeout: <timeout>s, secure: <yes/no>)"
- Prywatne składowe:
main.cpp: Zademonstruj łańcuch delegowania, tworząc połączenia za pomocą różnych konstruktorów. Wczytaj nazwę hosta i numer portu z wejścia (każdy w osobnym wierszu), a następnie:- Utwórz obiekt
Connectionza pomocą konstruktora domyślnego - Utwórz obiekt
Connection, używając tylko hosta z wejścia - Utwórz obiekt
Connection, używając hosta i portu z wejścia - Utwórz obiekt
Connectionz hostem i portem z wejścia, wartością timeout równą60i ustawionym natrueparametrem secure - Wypisz wynik
getInfo()dla każdego połączenia, po jednym wierszu
- Utwórz obiekt
Łańcuch delegowania przebiega następująco: konstruktor domyślny wywołuje konstruktor jednoargumentowy, który wywołuje konstruktor dwuargumentowy, a ten wywołuje główny konstruktor czteroargumentowy. Oznacza to, że komunikat "Connection configured" jest wypisywany raz dla każdego utworzonego obiektu, zawsze z konstruktora głównego.
W przypadku stanu zabezpieczenia w getInfo() wypisz "yes", jeśli secure ma wartość true, a w przeciwnym razie "no".
Dołącz plik nagłówkowy w main.cpp za pomocą #include "Connection.h".
Spróbuj swoich sił
#include <iostream>
#include <string>
#include "Connection.h"
using namespace std;
int main() {
// Odczytaj dane wejściowe
string host;
int port;
cin >> host;
cin >> port;
// TODO: Utwórz obiekt Connection za pomocą konstruktora domyślnego
// TODO: Utwórz obiekt Connection, używając tylko host z danych wejściowych
// TODO: Utwórz obiekt Connection, używając host i port z danych wejściowych
// TODO: Utwórz obiekt Connection z host i port z danych wejściowych oraz timeout=60 i secure=true
// TODO: Wypisz wynik getInfo() dla każdego połączenia, po jednym wierszu
return 0;
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrzneBudowanie i kompilacja C++Pliki nagłówkowe i pliki źródłowePrzestrzenie nazw i zakresWprowadzenie do programowania obiektowego w C++Klasy a obiektyWskaźnik „this”Metody (funkcje składowe)Atrybuty (składowe danych)Podstawy konstruktorów i destruktorówPowtórzenie – prosty kalkulator4Właściwości klas
Elementy instancji a elementy statyczneGettery i setteryStałe funkcje składoweSłowo kluczowe mutableMetody i zmienne statyczneFunkcje i klasy zaprzyjaźnionePodsumowanie – menedżer konta bankowego7Dziedziczenie
Podstawy dziedziczeniaPoziomy dostępu w dziedziczeniuKolejność wywołań konstruktora i destruktoraNadpisywanie metodFunkcje wirtualne i VTableWielokrotne dziedziczenieDziedziczenie wirtualnePowtórzenie — hierarchia pracowników2Zarządzanie pamięcią
Pamięć stosu a stertyWskaźniki i referencjePamięć dynamiczna (new/delete)Inteligentne wskaźniki w C++RAII w C++Podsumowanie — menedżer tablicy dynamicznej5Hermetyzacja
Specyfikatory dostępu w C++Specyfikatory dostępu — szczegółowoUkrywanie informacjiStruktura a klasaKlasy zagnieżdżone i wewnętrznePodsumowanie — system ewidencji studentów8Polimorfizm
Polimorfizm czasu kompilacji i wykonaniaPrzeciążanie funkcjiFunkcje wirtualne — powtórkaCzysto wirtualne funkcjeKlasy abstrakcyjneProjektowanie interfejsów w C++Rzutowanie dynamiczne i RTTIPodsumowanie — kalkulator kształtów3Konstruktory i destruktory
Konstruktor domyślnyKonstruktor z parametramiKonstruktor kopiującyKonstruktor przenoszącyListy inicjalizacyjne konstruktoraKonstruktory delegująceDestruktor — szczegółowe omówienieZasada trzech / pięciu / zeraPodsumowanie — klasa String6Przeciążanie operatorów
Wprowadzenie do przeciążania operatorówPrzeciążanie operatorów arytmetycznychPrzeciążanie operatorów porównaniaOperatory strumieniowePrzeciążanie operatora przypisaniaPrzeciążanie operatorów [] i ()Operatory konwersji typówPodsumowanie — klasa Matrix9Szablony
Szablony funkcjiSzablony klasSpecjalizacja szablonówSzablony wariadycznePodstawy SFINAE i cech typówPodsumowanie — kontener generycznyPoćwicz samodzielnie: Kompilator C++ online