Esistono cinque modi diversi per fondere le variabili. C'è una sovrapposizione tra loro, specialmente con il cast in stile C e tutti gli altri cast, ma ognuno ha il suo uso. È bello impararli tutti, quindi puoi usare il cast migliore per le tue particolari esigenze piuttosto che usare qualsiasi cast che funzioni. Se hai bisogno di un riferimento rapido, ti consiglio questo post StackOverflow.
Non sto discutendo di casting implicito qui per il semplice motivo che è un concetto di base con un numero quasi infinito di variazioni. Se scrivo flottante f = 10;
Ho implicitamente lanciato un intero su un float e ho memorizzato il suo risultato in f. È anche possibile eseguire il cast implicito di un oggetto di tipo B a un puntatore alla sua classe base A utilizzando l'operatore address-of o un riferimento alla sua classe base A eseguendo un normale assegnamento.
const_cast
L'operatore const_cast può aggiungere e rimuovere const e volatile. Usarlo per aggiungere uno di questi attributi va bene. È raro che lo faresti, ma se lo fai, puoi farlo.
La sua capacità di rimuovere const è qualcosa che non dovresti mai usare in un programma C ++ eccetto quando hai bisogno di chiamare una funzione in linguaggio C che non rispetti la cost-correttezza ma che non modifichi affatto l'oggetto. Se una funzione ha un parametro const e ne estrae la costanza utilizzando const_cast, la funzione interrompe il contratto implicito che non modificherà il parametro. Quindi spetta a te come autore di quella funzione assicurarti di non modificare l'oggetto; altrimenti, non dovresti usare const per il parametro dato che modifichi l'oggetto.
Se hai mai avuto bisogno di usare const_cast e un altro cast sullo stesso oggetto, usa const_cast last, dal momento che rimuovere la costanza da un oggetto potrebbe consentire modifiche involontarie se hai usato un cast successivo.
static_cast
L'operatore static_cast è utile per il casting:
In generale, ogni volta che si assegnano tipi fondamentali ad altri tipi fondamentali, utilizzare static_cast. In genere, static_cast dovrebbe essere la tua prima scelta di cast, poiché esegue tutto il controllo che può eseguire in fase di compilazione, quindi non hai aggiunto il controllo di runtime per rallentare il tuo programma.
dynamic_cast
L'operatore dynamic_cast è utile per eseguire il cast attraverso l'ereditarietà virtuale. static_cast può eseguire il cast da una classe derivata a una classe base, indipendentemente dal fatto che l'ereditarietà sia virtuale o meno. Dite, comunque, vi viene dato un oggetto di tipo A, ma sapete che in realtà è un oggetto di tipo B e che B eredita virtualmente da A. Se volete lanciare questo oggetto su B per usare le funzioni membro che solo B fornisce, è necessario utilizzare dynamic_cast.
Alcune cose su dynamic_cast. Innanzitutto, funziona solo sulle conversioni da puntatore a puntatore o da riferimento a riferimento. Secondo, non può effettivamente lanciare un oggetto da un A ad un B se l'oggetto non è, in effetti, un B (o di un tipo derivato da B). Un dynamic_cast pointer-to-pointer che fallisce restituisce null. Un errore di riferimento a riferimento genera a std :: bad_cast
eccezione.
reinterpret_cast
L'operatore reinterpret_cast è una conversione diretta con pochi buoni usi. La maggior parte delle sue operazioni danno risultati indefiniti. Ciò significa in pratica che dovresti leggere la documentazione del fornitore del compilatore prima di usarlo per qualsiasi cosa.
Un uso per questo, come abbiamo visto in StorageDurationSample
, è di lanciare un puntatore a un tipo intero abbastanza grande da tenerlo. Ciò fornisce l'indirizzo di memoria del puntatore, che può essere utile per le operazioni di debug e di tracciamento in cui è possibile scaricare i dati per registrare i file e creare core dump, ma potrebbe non essere in grado di eseguire facilmente un debugger. Lo vedrete usato legittimamente a volte per altri scopi, ma in generale, dovrebbe essere considerato come il cast di ultima istanza (escluso un cast in stile C, che viene dopo reinterpret_cast).
Il cast in stile C, (ad es., auto someData = (SomeType) dataOfSomeOtherType;
) non è tuo amico. Ne sei senza dubbio familiare da C #, dove è molto utile. In C #, se provi a fare un cast usando quella sintassi, e il cast non è valido, producerai una InvalidCastException. Ciò accade perché il CLR tiene traccia dei tipi di tutto ciò che hai creato e rileva i cast cattivi.
C ++ non verifica se il cast in stile C è valido, supponendo che venga compilato, ovviamente. C ++ presume solo che lo sia. Se è un cast male, e sei fortunato, il tuo programma si bloccherà immediatamente. Altrimenti, finirai con i dati in uno stato sconosciuto, che certamente si corromperanno in modi sottili e insidiosi.
Inoltre, a differenza degli altri cast, che puoi facilmente individuare cercando _cast<, C-style casts do not stick out. When you're scanning lots of code quickly, parentheses wrapped around text looks as much like a function call as it does a cast operation. You could use a regular expression search for this in Visual Studio 2012: \(.*\)[A-Za-z]. Even so, you are still forgoing all the benefits and protections of the other casts.
L'unica cosa che un cast in stile C può fare è che gli altri cast non possano lanciare un oggetto su una delle sue classi di ereditarietà protette o private. Non dovresti davvero farlo poiché, se hai bisogno dell'eredità pubblica, dovresti usare l'ereditarietà pubblica.
In breve, non usare i cast in stile C..
C'è un esempio, CastingSample, che dimostra i molti possibili tipi di casting. È incluso con il codice sorgente di questa serie. Nell'interesse della brevità, lo sto omettendo qui.
In questo articolo, abbiamo coperto il casting in C ++ e spero sia chiaro che non si dovrebbero usare i cast in stile C. Il prossimo articolo ingrandisce le stringhe in C++.
Questa lezione rappresenta un capitolo di C ++, un eBook gratuito del team di Syncfusion.