Przed standardem C++11, przy konieczności napisania kilku konstruktorów z różnymi parametrami, trzeba było duplikować kod inicjalizacji w każdym z nich, ponieważ nie było możliwości wywołania innego konstruktora wewnątrz konstruktorów klasy.
Niemozliwość użycia już istniejącej logiki inicjalizacji w innych konstruktorach prowadziła do duplikacji kodu i błędów przy zmianie logiki inicjalizacji: aktualizując jeden konstruktor, łatwo było zapomnieć o pozostałych.
Wraz z wprowadzeniem C++11 pojawił się mechanizm "konstruktory delegujące", który pozwala jednemu konstruktorowi klasy wywołać inny konstruktor tej samej klasy za pomocą składni listy inicjalizacji.
Przykład kodu:
class Widget { public: Widget() : Widget(0, "default") {} Widget(int n) : Widget(n, "user") {} Widget(int n, std::string name) : size(n), label(name) {} private: int size; std::string label; };
Teraz cała wspólna logika jest skoncentrowana w jednym "głównym" konstruktorze, a wszystko inne deleguje wywołanie.
Kluczowe cechy:
Czy można delegować wywołanie do innego konstruktora przez wywołanie funkcji wewnątrz ciała konstruktora?
Nie. Wywołanie konstruktora innego konstruktora jest możliwe tylko przez listę inicjalizacji, a nie wewnątrz ciała konstruktora. Jeśli wywołasz funkcję z ciała konstruktora, człony obiektu będą już zainicjalizowane.
Co się stanie, jeśli stworzysz "pierścień" delegacji między konstruktorami?
Cykliczna delegacja (na przykład A deleguje do B, a B – do A) prowadzi do błędu kompilacji C++: nie może być nieskończonej rekurencji między konstruktorami.
Czy można delegować wywołanie konstruktora klasy bazowej za pomocą konstruktora delegującego klasy pochodnej?
Nie. Konstruktory delegujące działają tylko w obrębie jednej klasy. Do wywołania konstruktora bazowego używa się osobnej składni:
class Base { public: Base(int) {} }; class Derived : public Base { public: Derived() : Base(42) {} };
Trzy konstruktory, każdy wyraźnie inicjalizuje pola, logika nie jest zsynchronizowana — zmiany wprowadzono tylko w jednym konstruktorze, pozostałe dwa są niepoprawne.
Zalety:
Wady:
Jeden główny konstruktor, pozostałe mu delegują, cała logika inicjalizacji jest scentralizowana.
Zalety:
Wady: