Qual è il significato di constin dichiarazioni come queste? Il constmi confonde.
class foobar
{
public:
operator int () const;
const char* foo() const;
};
Qual è il significato di constin dichiarazioni come queste? Il constmi confonde.
class foobar
{
public:
operator int () const;
const char* foo() const;
};
Risposte:
Quando aggiungi la constparola chiave a un metodo, il thispuntatore diventa essenzialmente un puntatore constall'oggetto e non puoi quindi modificare i dati dei membri. (A meno che non lo usi mutable, ne parleremo più avanti).
La constparola chiave fa parte della firma delle funzioni, il che significa che è possibile implementare due metodi simili, uno che viene chiamato quando l'oggetto è conste uno che non lo è.
#include <iostream>
class MyClass
{
private:
int counter;
public:
void Foo()
{
std::cout << "Foo" << std::endl;
}
void Foo() const
{
std::cout << "Foo const" << std::endl;
}
};
int main()
{
MyClass cc;
const MyClass& ccc = cc;
cc.Foo();
ccc.Foo();
}
Questo produrrà
Foo
Foo const
Nel metodo non const è possibile modificare i membri dell'istanza, cosa che non è possibile eseguire nella constversione. Se si modifica la dichiarazione del metodo nell'esempio sopra con il codice riportato di seguito, verranno visualizzati degli errori.
void Foo()
{
counter++; //this works
std::cout << "Foo" << std::endl;
}
void Foo() const
{
counter++; //this will not compile
std::cout << "Foo const" << std::endl;
}
Questo non è completamente vero, perché è possibile contrassegnare un membro come mutablee un constmetodo può quindi modificarlo. È principalmente usato per contatori interni e cose. La soluzione sarebbe il seguente codice.
#include <iostream>
class MyClass
{
private:
mutable int counter;
public:
MyClass() : counter(0) {}
void Foo()
{
counter++;
std::cout << "Foo" << std::endl;
}
void Foo() const
{
counter++; // This works because counter is `mutable`
std::cout << "Foo const" << std::endl;
}
int GetInvocations() const
{
return counter;
}
};
int main(void)
{
MyClass cc;
const MyClass& ccc = cc;
cc.Foo();
ccc.Foo();
std::cout << "Foo has been invoked " << ccc.GetInvocations() << " times" << std::endl;
}
quale sarebbe uscita
Foo
Foo const
Foo has been invoked 2 times
La const significa che il metodo promette di non alterare alcun membro della classe. Saresti in grado di eseguire i membri dell'oggetto che sono così contrassegnati, anche se l'oggetto stesso fosse segnato const:
const foobar fb;
fb.foo();
sarebbe legale.
Vedi quanti e quali sono gli usi di "const" in C ++? per maggiori informazioni.
Il constqualificatore indica che i metodi possono essere chiamati su qualsiasi valore di foobar. La differenza viene quando si considera di chiamare un metodo non const su un oggetto const. Valuta se il tuo foobartipo aveva la seguente dichiarazione del metodo extra:
class foobar {
...
const char* bar();
}
Il metodo bar()non è const e vi si può accedere solo da valori non const.
void func1(const foobar& fb1, foobar& fb2) {
const char* v1 = fb1.bar(); // won't compile
const char* v2 = fb2.bar(); // works
}
L'idea alla base constè però quella di contrassegnare metodi che non altereranno lo stato interno della classe. Questo è un concetto potente ma non è effettivamente applicabile in C ++. È più una promessa che una garanzia. E uno che è spesso rotto e facilmente rotto.
foobar& fbNonConst = const_cast<foobar&>(fb1);
constè quella di segnare metodi che non altereranno lo stato interno della classe". Questo è davvero quello che stavo cercando.
const?
Queste const indicano che il compilatore si guasta se il metodo "con const" modifica i dati interni.
class A
{
public:
A():member_()
{
}
int hashGetter() const
{
state_ = 1;
return member_;
}
int goodGetter() const
{
return member_;
}
int getter() const
{
//member_ = 2; // error
return member_;
}
int badGetter()
{
return member_;
}
private:
mutable int state_;
int member_;
};
Il test
int main()
{
const A a1;
a1.badGetter(); // doesn't work
a1.goodGetter(); // works
a1.hashGetter(); // works
A a2;
a2.badGetter(); // works
a2.goodGetter(); // works
a2.hashGetter(); // works
}
Leggi questo per maggiori informazioni
constfunzioni membro che non menziona mutevole è nella migliore delle ipotesi incompleta.
La risposta di Blair è nel segno.
Tuttavia, è presente un mutablequalificatore che può essere aggiunto ai membri dei dati di una classe. Qualsiasi membro così contrassegnato può essere modificato in un constmetodo senza violare il constcontratto.
Potresti voler usare questo (per esempio) se vuoi che un oggetto ricordi quante volte viene chiamato un metodo particolare, senza influire sulla costanza "logica" di quel metodo.
Significato di una funzione membro Cost in C ++ Conoscenza comune: la programmazione intermedia essenziale fornisce una chiara spiegazione:
Il tipo di questo puntatore in una funzione membro non const di una classe X è X * const. Cioè, è un puntatore costante a una X non costante (vedere Const Pointers e Pointers to Const [7, 21]). Poiché l'oggetto a cui si riferisce questo non è const, può essere modificato. Il tipo di questo in una funzione membro const di una classe X è const X * const. Cioè, è un puntatore costante a una X costante. Poiché l'oggetto a cui si riferisce è const, non può essere modificato. Questa è la differenza tra le funzioni membro const e non const.
Quindi nel tuo codice:
class foobar
{
public:
operator int () const;
const char* foo() const;
};
Puoi pensarlo come questo:
class foobar
{
public:
operator int (const foobar * const this) const;
const char* foo(const foobar * const this) const;
};
thisnon lo è const. Il motivo per cui non può essere modificato è che si tratta di un valore.
quando usi constnella firma del metodo (come hai detto const char* foo() const;:) stai dicendo al compilatore che la memoria indicata da thisnon può essere modificata con questo metodo (che è fooqui).
Vorrei aggiungere il seguente punto.
Puoi anche renderlo un const &econst &&
Così,
struct s{
void val1() const {
// *this is const here. Hence this function cannot modify any member of *this
}
void val2() const & {
// *this is const& here
}
void val3() const && {
// The object calling this function should be const rvalue only.
}
void val4() && {
// The object calling this function should be rvalue reference only.
}
};
int main(){
s a;
a.val1(); //okay
a.val2(); //okay
// a.val3() not okay, a is not rvalue will be okay if called like
std::move(a).val3(); // okay, move makes it a rvalue
}
Sentiti libero di migliorare la risposta. Non sono un esperto
*thisè sempre un lvalue, anche se la funzione membro è qualificata rvalue-ref e viene chiamata su un rvalue. Esempio .
La parola chiave const utilizzata con la dichiarazione della funzione specifica che si tratta di una funzione membro const e che non sarà in grado di modificare i membri dei dati dell'oggetto.
https://isocpp.org/wiki/faq/const-correctness#const-member-fns
Che cos'è una "
constfunzione membro"?Una funzione membro che controlla (piuttosto che muta) il suo oggetto.
Una
constfunzione membro è indicata da unconstsuffisso subito dopo l'elenco dei parametri della funzione membro. Le funzioni membro con unconstsuffisso sono chiamate "funzioni membro const" o "ispettori". Le funzioni membro senzaconstsuffisso sono chiamate "funzioni membro non const" o "mutatori".class Fred { public: void inspect() const; // This member promises NOT to change *this void mutate(); // This member function might change *this }; void userCode(Fred& changeable, const Fred& unchangeable) { changeable.inspect(); // Okay: doesn't change a changeable object changeable.mutate(); // Okay: changes a changeable object unchangeable.inspect(); // Okay: doesn't change an unchangeable object unchangeable.mutate(); // ERROR: attempt to change unchangeable object }Il tentativo di chiamare
unchangeable.mutate()è un errore rilevato al momento della compilazione. Non esiste spazio di runtime o penalità di velocità perconste non è necessario scrivere casi di test per verificarlo in fase di runtime.La funzione trailing
constoninspect()member dovrebbe essere usata per indicare che il metodo non cambierà lo stato astratto (visibile al client) dell'oggetto . Ciò è leggermente diverso dal dire che il metodo non cambierà i "bit grezzi" della struttura dell'oggetto. I compilatori C ++ non possono interpretare "bitwise" a meno che non siano in grado di risolvere il problema di aliasing, che normalmente non può essere risolto (vale a dire che potrebbe esistere un alias non const che potrebbe modificare lo stato dell'oggetto). Un'altra (importante) intuizione di questo problema di aliasing: puntare a un oggetto con un puntatore a const non garantisce che l'oggetto non cambi; promette semplicemente che l'oggetto non cambierà tramite quel puntatore .