Prima dello standard C++11, se era necessario scrivere più costruttori con parametri diversi, era necessario duplicare il codice di inizializzazione in ognuno di essi, poiché non era possibile chiamare un altro costruttore all'interno dei costruttori di una classe.
L'impossibilità di utilizzare la logica di inizializzazione esistente in altri costruttori portava alla duplicazione del codice e a errori quando si modificava la logica di inizializzazione: aggiornando un costruttore, era facile dimenticare gli altri.
Con l'uscita di C++11 è stato introdotto il meccanismo dei "costruttori deleganti", che consente a un costruttore di una classe di chiamare un altro costruttore della stessa classe attraverso la sintassi della lista di inizializzazione.
Esempio di codice:
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; };
Ora tutta la logica comune è concentrata in un "costruttore principale", mentre gli altri delegano la chiamata.
Caratteristiche chiave:
È possibile delegare la chiamata a un altro costruttore tramite la chiamata a una funzione all'interno del corpo del costruttore?
No. La chiamata a un costruttore da un altro costruttore è possibile solo attraverso la lista di inizializzazione e non all'interno del corpo del costruttore. Se si chiama una funzione dal corpo del costruttore, i membri dell'oggetto saranno già stati inizializzati.
Cosa succede se si crea un "anello" di delegazione tra costruttori?
La delegazione circolare (ad esempio, A delega a B, e B delega a A) porta a un errore di compilazione in C++: non può esserci una ricorsione infinita tra costruttori.
È possibile delegare la chiamata al costruttore della classe base usando un costruttore delegante della classe derivata?
No. I costruttori deleganti funzionano solo all'interno di una classe. Per chiamare il costruttore base si utilizza una sintassi separata:
class Base { public: Base(int) {} }; class Derived : public Base { public: Derived() : Base(42) {} };
Tre costruttori, ognuno inizializza esplicitamente i campi, la logica non è sincronizzata — se si modifica solo un costruttore, gli altri due diventano errati.
Pro:
Contro:
Un costruttore principale, gli altri delegano a lui, tutta la logica di inizializzazione è centralizzata.
Pro:
Contro: