Conversioni di Tipo (Type Conversions)
Le conversioni di tipo avvengono costantemente per far scorrere agevolmente i calcoli. Per questo, in assenza di regole stringenti, il compilatore avvia le conversioni Implicite.
Conversioni Implicite e Pericolose
Section titled “Conversioni Implicite e Pericolose”Abbiamo già visto la “promozione intera” tra tipi piccoli e int. Esistono conversioni benigne (un float passa a double senza perdere informazioni).
Purtroppo il C++ si distingue per un brutto vizio: permette le Conversioni di Stringimento (Narrowing Conversions) silenti.
Se provi ad assegnare un double in un uint8_t, per il C++ è tutto legale: semplicemente porterà via (troncherà) l’intero ammontare frazionale e taglierà i bit restanti per incastrarsi nel contenitore piccolo. La precisione scientifica viene brutalmente annientata in background. E lo stesso accade se cerchi di far combaciare interi Signed e Unsigned (dove ad es. si manifesta Undefined Behavior o valori esasperati legati all’Implementation).
Il rimedio lo abbiamo studiato nel capitolo precedente: inizializzazione tramite parentesi graffe {} (Braced Initialization). I compilatori sono programmati per respingere istantaneamente una conversione Narrowing racchiusa tra parentesi graffe: il codice uint8_t y{ precision }; lancerà un graditissimo Errore di Compilazione salvandoti la pelle.
Cast Stile-C
Section titled “Cast Stile-C”Per mantenere l’anacronistica e malsana compatibilità, in C++ è sempre presente il cast C-style: (int)valore.
È orrendo, invisibile durante un parsing visivo ed enormemente più pericoloso dei named-casts (perché aggirerà silenziosamente sia lo static_cast che i controlli reinterpret, comportandosi in ogni contesto in base a dove finisce).
void funzione_cast(const char* read_only) { // Sbagliatissimo! // Stiamo eludendo la sicurezza del 'const' implicitamente. auto as_unsigned = (unsigned char*)read_only; // Se modifichiamo l'as_unsigned, avremo un crash su macchine Windows.}Evitalo e affidati per tutta la vita ai static_cast, const_cast e reinterpret_cast.
Conversioni in Tipi Definiti dall’Utente
Section titled “Conversioni in Tipi Definiti dall’Utente”Un po’ come sovrascriviamo gli operatori, possiamo “insegnare” a una nostra Classe custom come reagire qualora il programmatore decida di assegnarla, esplicitamente o implicitamente, a una variabile di tipo standard! È utile se la nostra classe “fa finta” di essere un intero arricchito di feature extra (come il CheckedInteger).
Si esegue inserendo la firma fissa operator Tipo() const { } dentro la classe.
Se non vuoi le fastidiose sorprese tipiche delle conversioni auto-magiche che si incastrano dove non avresti voluto, puoi frenare questo comportamento premettendo explicit. L’unico modo per invocare la conversione diventerà usare la forza manuale: static_cast<int>(the_answer).