In C++, se un costruttore può essere chiamato con un solo argomento, per impostazione predefinita è considerato implicit. Un costruttore di questo tipo può essere utilizzato per conversioni di tipo implicite. Per proteggersi da questo, si utilizza la parola chiave explicit.
explicit vietano le conversioni implicite.L'uso di explicit consente di evitare conversioni inaspettate che possono verificarsi, ad esempio, quando si passa un argomento di tipo non corrispondente a una funzione o durante l'inizializzazione di una variabile.
Esempio:
struct Foo { explicit Foo(int x) { /* ... */ } }; Foo a = 10; // Errore, explicit vieta l'inizializzazione implicita Foo b(10); // Ok
Se non ci fosse stato explicit, la scrittura Foo a = 10; sarebbe stata consentita e potrebbe aver portato a bug inaspettati.
Domanda: Tutti i costruttori dichiarati con explicit non possono essere chiamati durante l'inizializzazione con = ?
Risposta comune: Sì, explicit vieta qualsiasi inizializzazione con =.
Risposta corretta: explicit vieta solo le conversioni implicite. Con l'inizializzazione diretta (ClassName obj(param);) il costruttore explicit viene chiamato. Con l'inizializzazione per copia (ClassName obj = param;) – no.
Esempio:
struct A { explicit A(int) {} }; A x = 1; // Errore A y(1); // OK
Storia: In un progetto è stato scritto un costruttore senza explicit, consentendo l'inizializzazione tramite tipi, il che ha portato a conversioni automatiche inaspettate degli argomenti delle funzioni. Questo ha causato errori nascosti e ha reso difficile il debug.
Storia: Un sviluppatore non ha messo explicit per il costruttore di un contenitore e il costruttore predefinito ha iniziato ad essere chiamato inaspettatamente durante l'assegnazione o la trasmissione di altri tipi. Risultato — logica di creazione degli oggetti non corretta e comportamento imprevedibile.
Storia: Un programmatore inesperto ha dichiarato un costruttore explicit, ma è rimasto sorpreso che l'inizializzazione diretta con le parentesi tonde funziona, pensando che explicit lo bloccasse. Questo ha portato a non utilizzare schemi sicuri e utili e a codice superfluo nel progetto.