Qual é o significado de const
declarações como essas? A const
me confunde.
class foobar
{
public:
operator int () const;
const char* foo() const;
};
Qual é o significado de const
declarações como essas? A const
me confunde.
class foobar
{
public:
operator int () const;
const char* foo() const;
};
Respostas:
Quando você adiciona a const
palavra-chave a um método, o this
ponteiro se torna essencialmente um ponteiro para um const
objeto e, portanto, não é possível alterar nenhum dado de membro. (A menos que você use mutable
, mais sobre isso mais tarde).
A const
palavra-chave faz parte da assinatura das funções, o que significa que você pode implementar dois métodos semelhantes, um chamado quando o objeto é const
e outro que não é.
#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();
}
Isso produzirá
Foo
Foo const
No método non-const, você pode alterar os membros da instância, o que não é possível na const
versão. Se você alterar a declaração do método no exemplo acima para o código abaixo, você receberá alguns erros.
void Foo()
{
counter++; //this works
std::cout << "Foo" << std::endl;
}
void Foo() const
{
counter++; //this will not compile
std::cout << "Foo const" << std::endl;
}
Isso não é completamente verdade, porque você pode marcar um membro como mutable
e um const
método pode alterá-lo. É usado principalmente para contadores internos e outras coisas. A solução para isso seria o código abaixo.
#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;
}
o que produziria
Foo
Foo const
Foo has been invoked 2 times
A const significa que o método promete não alterar nenhum membro da classe. Você seria capaz de executar os membros do objeto que estão tão marcados, mesmo se o próprio objeto estiver marcado const
:
const foobar fb;
fb.foo();
seria legal.
Veja Quantos e quais são os usos de "const" em C ++? Para maiores informações.
O const
qualificador significa que os métodos podem ser chamados com qualquer valor de foobar
. A diferença ocorre quando você considera chamar um método não-const em um objeto const. Considere se seu foobar
tipo possui a seguinte declaração de método extra:
class foobar {
...
const char* bar();
}
O método bar()
é não const e só pode ser acessado a partir de valores não const.
void func1(const foobar& fb1, foobar& fb2) {
const char* v1 = fb1.bar(); // won't compile
const char* v2 = fb2.bar(); // works
}
A idéia por trás disso const
é marcar métodos que não alterem o estado interno da classe. Esse é um conceito poderoso, mas não é realmente aplicável em C ++. É mais uma promessa do que uma garantia. E um que é frequentemente quebrado e facilmente quebrado.
foobar& fbNonConst = const_cast<foobar&>(fb1);
const
é marcar métodos que não alteram o estado interno da classe". Era realmente o que eu estava procurando.
const
?
Estes const significam que o compilador irá Erro se o método 'with const' alterar dados internos.
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_;
};
O teste
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
}
Leia isto para mais informações
const
funções-membro que não menciona mutável é incompleta, na melhor das hipóteses.
A resposta de Blair está na marca.
No entanto, observe que há um mutable
qualificador que pode ser adicionado aos membros de dados de uma classe. Qualquer membro marcado pode ser modificado em um const
método sem violar o const
contrato.
Você pode usar isso (por exemplo) se desejar que um objeto se lembre de quantas vezes um método específico é chamado, sem afetar a constância "lógica" desse método.
Significado de uma função de membro Const no C ++ Common Knowledge: A programação intermediária essencial fornece uma explicação clara:
O tipo do ponteiro this em uma função de membro não const de uma classe X é X * const. Ou seja, é um ponteiro constante para um X não constante (consulte Const Pointers e Pointers to Const [7, 21]). Como o objeto ao qual isso se refere não é const, ele pode ser modificado. O tipo disso em uma função de membro const de uma classe X é const X * const. Ou seja, é um ponteiro constante para um X constante. Como o objeto ao qual isso se refere é const, ele não pode ser modificado. Essa é a diferença entre as funções de membro const e não-const.
Então, no seu código:
class foobar
{
public:
operator int () const;
const char* foo() const;
};
Você pode pensar assim:
class foobar
{
public:
operator int (const foobar * const this) const;
const char* foo(const foobar * const this) const;
};
this
não é const
. A razão pela qual não pode ser modificado é que é um valor inicial.
Quando você usa const
a assinatura do método (como você disse const char* foo() const;
:), está dizendo ao compilador que a memória apontada por this
não pode ser alterada por esse método (que está foo
aqui).
Eu gostaria de acrescentar o seguinte ponto.
Você também pode fazer -lhe um const &
econst &&
Assim,
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
}
Sinta-se livre para melhorar a resposta. Eu não sou especialista
*this
é sempre um lvalue, mesmo se a função de membro for qualificada para rvalue-ref e for chamada em um rvalue. Exemplo .
A palavra-chave const usada com a declaração da função especifica que é uma função de membro const e não poderá alterar os membros de dados do objeto.
https://isocpp.org/wiki/faq/const-correctness#const-member-fns
O que é uma "
const
função de membro"?Uma função de membro que inspeciona (em vez de modifica) seu objeto.
Uma
const
função de membro é indicada por umconst
sufixo logo após a lista de parâmetros da função de membro. As funções de membro com umconst
sufixo são chamadas de "funções de membro const" ou "inspetores". As funções de membro semconst
sufixo são chamadas de "funções de membro não const" ou "mutadores".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 }
A tentativa de chamada
unchangeable.mutate()
é um erro detectado em tempo de compilação. Não há espaço para o tempo de execução ou penalidade de velocidadeconst
, e você não precisa escrever casos de teste para verificá-lo no tempo de execução.A função de membro
const
à direitainspect()
deve ser usada para significar que o método não alterará o estado abstrato do objeto (visível ao cliente). Isso é um pouco diferente de dizer que o método não altera os “bits brutos” da estrutura do objeto. Os compiladores C ++ não podem usar a interpretação “bit a bit”, a menos que possam resolver o problema de aliasing, que normalmente não pode ser resolvido (ou seja, poderia existir um alias não const que pudesse modificar o estado do objeto). Outro insight (importante) desse problema de alias: apontar para um objeto com um ponteiro para const não garante que o objeto não seja alterado; apenas promete que o objeto não será alterado por esse ponteiro .