Traduzioni di questa pagina?:

const

La parola chiave const può essere usata per indicare al compilatore che una certa variabile non deve essere più modificata una volta che è stata inizializzata, oppure per dichiarare metodi di una classe che non possono alterare alcuna variabile membro della stessa classe.

Uso

Una pratica corretta nell'uso di const è quella di usarlo per proteggere dati che non devono essere sovrascritti. Questo deve essere fatto nella fase di progettazione poiché forzare un const in un programma dopo che ha già raggiunto uno stadio di maturazione dello sviluppo avrebbe considerevoli effetti a cascata.

La parola const può assumere molti significati, può essere usata in numerose posizioni della sintassi (anche in alcune piuttosto innaturali)

Dichiarazioni

Per capire cosa const sta proteggendo bisogna leggere da destra a sinistra.

const char * str; // puntatore a caratteri che non possono essere cambiati (anche se il puntatore può cambiare)
char const * str; // come prima, solo un modo alternativo per scriverlo
char * const str; // il puntatore non può essere modificato (anche se i caratteri nel buffer possono cambiare)

Analogamente per le reference (non ha senso applicare un const a una reference, dato che il senso stesso delle reference è che non possono essere cambiate per riferire ad un altro oggetto):

const char & str; // reference verso un carattere che non può essere cambiato
char const & str; // funziona come alla riga precedente

Finora sembra abbastanza semplice, ma costruzioni più complicate possono essere difficili da interpretare. Esempio:

char * const * data; // puntatore ad un puntatore non modificabile che punta ad un array di caratteri
char const ** data;  // puntatore ad un puntatore di caratteri non modificabili
const char ** data;  // puntatore ad un puntatore di caratteri non modificabili
char ** const data;  // puntatore non modificabile che punta ad un puntatore di caratteri
char * const * const data; // puntatore non modificabile verso un puntatore non modificabile di caratteri

Esiste tra alcuni programmatori la convinzione che sia obbligatorio mettere const dopo il tipo dati, ma in realtà può essere scritto sia prima che dopo il tipo, se è un tipo dati regolare e non un puntatore (e.g. “char”). Usate la forma che si adatta meglio al vostro codice e agli standard di sviluppo del codice adottati dalla vostra organizzazione semplicemente cercando di essere consistenti. Se volete che const si applichi al puntatore la parola chiave deve apparire dopo l'asterisco.

E' inoltre una buona pratica dichiarare certi campi di un oggetto come const se questi esprimono una proprietà dell'oggetto che non cambierà durante la vita di esso.

Parametri

L'uso più comune di const è di proteggere dati da cambiamenti che potrebbero essere fatti tramite puntatori o reference

   void func ( const MyObject * data ); // MyObject non può essere cambiato in func
   void func ( const MyObject & data ); // MyObject non può essere cambiato in func

Notate che il posizionamento di const prima o dopo è irrilevante. Le righe seguenti sono equivalenti a quelle scritte sopra

void func ( MyObject const * data ); // same as ( const MyObject * )
void func ( MyObject const & data ); // same as ( const MyOjbect & )

Posizionare const dopo il puntatore o la reference cambia i suoi effetti. Un const che segue il puntatore cambia solo il puntatore, non i dati che questo punta.

void func ( MyObject * const data ); // Protezione superflua di 'data' poiché passato per valore

All'interno di func siete liberi di manipolare MyObject, ma non il puntatore a MyObject. Tuttavia, siccome il puntatore è una variabile locale della funzione questo non è di grande utilità. Anche se cambiaste il valore del puntatore nulla verrebbe alterato al di fuori della funzione.

Posizionare const dopo una reference è completamente inutile e deve essere evitato. Le reference sono già implicitamente const

void func ( MyObject & const data ); // protezione inutile della reference a MyObject

In questo caso const protegge la reference, che non può venir manipolata.

A volte è utile ritornare dati privati di un oggetto preservando la loro non modificabilità al di fuori di esso.

const MyObject & MyClass::func ( MyObject & data ); // l'oggetto MyObject ritornato da func non può essere cambiato

Metodi

Spesso metodi di un istanza non manipolano dati interni all'oggetto. Questi metodi (spesso chiamati accessors) dovrebbero essere dichiarati const

L'effetto di questo è che il puntatore this all'interno del metodo, invece di essere definito come “MyClass *” sarà un “const MyClass *” così che l'oggetto non può essere modificato tramite questo puntatore.

void MyClass::func ( MyOjbect & data ) const; // Questa funzione non manipola dati della classe

Da notare che dichiarare un oggetto come const funziona come filtro sulla sua interfaccia dato che solo i metodi dichiarati const possono essere chiamati. Il motivo è legato a quanto già detto: chiamare un metodo di un oggetto 'const' significa passare implicitamente un puntatore all'oggetto di tipo “const MyClass *” e quindi un puntatore di un oggetto non modificabile.

void MyClass::const_func() const;
void MyClass::func();
 
const MyClass object;
 
object.const_func(); // ok
object.func(); // non si può chiamare un metodo non-const di un oggetto const

Per la stessa ragione all'interno di un metodo const si può chiamare solo altri metodi const dell'oggetto.

Argomenti correlati: const_cast, mutable