Funzioni di Conversione Nominate (C++ Casts)
Le conversioni di tipo esplicite (Casting) in C sono brutali: (int)valore. In C++, queste sono state sostituite da Conversioni Nominate (Named Conversions) che sfruttano una sintassi simile a quella dei template. Usare i cast in stile C++ è più sicuro e segnala chiaramente le tue intenzioni agli altri programmatori (o a chi usa grep per cercare conversioni pericolose).
La sintassi universale è: tipo_cast<TipoDesiderato>(oggetto_da_convertire)
Esistono tre conversioni principali:
1. const_cast
Section titled “1. const_cast”L’unico scopo di const_cast è togliere (o aggiungere, seppur raro) il qualificatore const da una referenza o da un puntatore. Lo userai quasi esclusivamente se devi dialogare con un’API legacy che si aspetta un puntatore non-const ma tu sai per certo che non lo modificherà.
Attenzione: Usare
const_castper eludere la sicurezza e poi modificare un dato nato come costruttivamenteconstgenera Comportamento Indefinito (UB).
void funzione_legacy(char* str) { /* fa finta di niente, ma non modifica str */ }
const char* my_string = "Hello";// funzione_legacy(my_string); // ERRORE!funzione_legacy(const_cast<char*>(my_string)); // OK!2. static_cast
Section titled “2. static_cast”È il “cavallo di battaglia”. Esegue conversioni ben definite, come convertire un int a float, o convertire puntatori a void* verso un tipo specifico conosciuto. Inverte conversioni implicite ben definite.
Se provassimo a usare static_cast per acrobazie impossibili (es. da char* a float*), il compilatore andrebbe gentilmente in errore di compilazione, salvandoti la vita.
3. reinterpret_cast
Section titled “3. reinterpret_cast”Ed ecco l’artigliera pesante. Quando le difese cedono e devi dire al compilatore “Stai zitto e tratta questi bit in memoria come dico io”, usi reinterpret_cast.
È onnipresente nel software embedded (es. mappare un puntatore a un registro hardware mappato in memoria all’indirizzo fisico 0x1000).
int main() { // Obblighiamo il compilatore a leggere all'indirizzo 0x1000 come se fosse un intero auto timer = reinterpret_cast<const unsigned long*>(0x1000); // printf("Timer: %lu", *timer); // Fallirebbe su un normale PC, funziona su microcontroller!}