C++
parola chiave const
Ricerca…
Sintassi
- const Type myVariable = initial; // Dichiara una variabile const; non può essere cambiato
- const Type & myReference = myVariable; // Dichiara un riferimento a una variabile const
- const Type * myPointer = & myVariable; // Dichiara un puntatore-a-const. Il puntatore può cambiare, ma il membro dati sottostante non può essere modificato tramite il puntatore
- Digita * const myPointer = & myVariable; // Dichiara un puntatore const. Il puntatore non può essere riassegnato per puntare a qualcos'altro, ma il membro dati sottostante può essere modificato
- const Type * const myPointer = & myVariable; // Dichiara un const pointer-to-const.
Osservazioni
Una variabile contrassegnati come const
non può essere modificata 1. Il tentativo di chiamare qualsiasi operazione non const su di esso comporterà un errore del compilatore.
1: Beh, può essere cambiato tramite const_cast
, ma non dovresti quasi mai usarlo
Const variabili locali
Dichiarazione e uso.
// a is const int, so it can't be changed
const int a = 15;
a = 12; // Error: can't assign new value to const variable
a += 1; // Error: can't assign new value to const variable
Legame di riferimenti e puntatori
int &b = a; // Error: can't bind non-const reference to const variable
const int &c = a; // OK; c is a const reference
int *d = &a; // Error: can't bind pointer-to-non-const to const variable
const int *e = &a // OK; e is a pointer-to-const
int f = 0;
e = &f; // OK; e is a non-const pointer-to-const,
// which means that it can be rebound to new int* or const int*
*e = 1 // Error: e is a pointer-to-const which means that
// the value it points to can't be changed through dereferencing e
int *g = &f;
*g = 1; // OK; this value still can be changed through dereferencing
// a pointer-not-to-const
Puntatori Const
int a = 0, b = 2;
const int* pA = &a; // pointer-to-const. `a` can't be changed through this
int* const pB = &a; // const pointer. `a` can be changed, but this pointer can't.
const int* const pC = &a; // const pointer-to-const.
//Error: Cannot assign to a const reference
*pA = b;
pA = &b;
*pB = b;
//Error: Cannot assign to const pointer
pB = &b;
//Error: Cannot assign to a const reference
*pC = b;
//Error: Cannot assign to const pointer
pC = &b;
Funzioni membro Const
Le funzioni membro di una classe possono essere dichiarate const
, che dice al compilatore e ai futuri lettori che questa funzione non modificherà l'oggetto:
class MyClass
{
private:
int myInt_;
public:
int myInt() const { return myInt_; }
void setMyInt(int myInt) { myInt_ = myInt; }
};
In una funzione membro const
, this
puntatore è effettivamente un const MyClass *
invece di un MyClass *
. Ciò significa che non è possibile modificare alcuna variabile membro all'interno della funzione; il compilatore emetterà un avvertimento. Quindi setMyInt
non può essere dichiarato const
.
Dovresti quasi sempre contrassegnare le funzioni membro come const
quando possibile. Solo le funzioni membro const
possono essere chiamate su const MyClass
.
static
metodi static
non possono essere dichiarati come const
. Questo perché un metodo statico appartiene a una classe e non è chiamato su oggetto; quindi non può mai modificare le variabili interne dell'oggetto. Quindi dichiarare static
metodi static
come const
sarebbe ridondante.
Evitare la duplicazione del codice nei metodi getter const e non-const.
Nei metodi C ++ che differiscono solo dal const
qualificatore possono essere sovraccaricati. A volte potrebbe essere necessario disporre di due versioni di getter che restituiscono un riferimento ad un membro.
Lascia che Foo
sia una classe, che ha due metodi che eseguono operazioni identiche e restituisce un riferimento a un oggetto di tipo Bar
:
class Foo
{
public:
Bar& GetBar(/* some arguments */)
{
/* some calculations */
return bar;
}
const Bar& GetBar(/* some arguments */) const
{
/* some calculations */
return bar;
}
// ...
};
L'unica differenza tra loro è che un metodo è non-const e restituisce un riferimento non-const (che può essere utilizzato per modificare l'oggetto) e il secondo è const e restituisce const riferimento.
Per evitare la duplicazione del codice, c'è la tentazione di chiamare un metodo da un altro. Tuttavia, non possiamo chiamare il metodo non-const da quello const. Ma possiamo chiamare il metodo const da quello non const. Ciò richiederà di usare 'const_cast' per rimuovere il qualificatore const.
La soluzione è:
struct Foo
{
Bar& GetBar(/*arguments*/)
{
return const_cast<Bar&>(const_cast<const Foo*>(this)->GetBar(/*arguments*/));
}
const Bar& GetBar(/*arguments*/) const
{
/* some calculations */
return foo;
}
};
Nel codice qui sopra, chiamiamo la versione const di GetBar
dalla GetBar
non-const GetBar
in tipo const: const_cast<const Foo*>(this)
. Siccome chiamiamo il metodo const da non-const, l'oggetto stesso è non-const, e il cast via è const.
Esaminare il seguente esempio più completo:
#include <iostream>
class Student
{
public:
char& GetScore(bool midterm)
{
return const_cast<char&>(const_cast<const Student*>(this)->GetScore(midterm));
}
const char& GetScore(bool midterm) const
{
if (midterm)
{
return midtermScore;
}
else
{
return finalScore;
}
}
private:
char midtermScore;
char finalScore;
};
int main()
{
// non-const object
Student a;
// We can assign to the reference. Non-const version of GetScore is called
a.GetScore(true) = 'B';
a.GetScore(false) = 'A';
// const object
const Student b(a);
// We still can call GetScore method of const object,
// because we have overloaded const version of GetScore
std::cout << b.GetScore(true) << b.GetScore(false) << '\n';
}