Skip to content

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.

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.

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).