Respostas:
Leia isto: https://isocpp.org/wiki/faq/const-correctness
O final const
significa que a funçãoMethod3
não modifica os membros não mutáveis de sua classe.
const int* const
significa um ponteiro constante para um int constante: ou seja, um ponteiro que não pode ser alterado, para um int que não pode ser alterado: a única diferença entre isso e const int&
é que pode sernull
const int* const&
significa uma referência a um ponteiro constante para um int constante. Normalmente, os ponteiros não são passados por referência; const int* &
faz mais sentido porque significaria que o ponteiro poderia ser alterado durante a chamada do método, que seria a única razão que vejo para passar um ponteiro por referência, const int* const&
é para todas as intenções e finalidades iguais, const int* const
exceto que é provavelmente menos eficiente como ponteiros são tipos de dados antigos simples (POD) e devem, em geral, ser passados por valor.
É mais fácil de entender se você reescrever isso como o equivalente completamente
// v───v───v───v───v───v───v───v───v───v───v───v─┬┐
// ││
// v──#1 v─#2 v──#3 v─#4 #5
int const * const Method3(int const * const&) const;
em seguida, leia da direita para a esquerda.
# 5 diz que toda a declaração de função à esquerda é const
, o que implica que esta é necessariamente uma função-membro em vez de uma função livre.
# 4 diz que o ponteiro à esquerda é const
(não pode ser alterado para apontar para um endereço diferente).
# 3 diz que o int
à esquerda é const
(não pode ser alterado para ter um valor diferente).
# 2 diz que o ponteiro à esquerda é const
.
# 1 diz que int
à esquerda éconst
.
Juntando tudo isso, você pode ler isso como uma const
função de membro chamada Method3
que faz referência a um const
ponteiro para um int const
(ou a const int
, se preferir) e retorna um const
ponteiro para um int const
( const int
).
(Nb # 2 é totalmente supérfluo .)
Em primeiro lugar, const T
é equivalente a T const
.
const int* const
é portanto equivalente a int const * const
.
Ao ler expressões com muitos const
tokens e ponteiros, sempre tente lê-los da direita para a esquerda (após aplicar a transformação acima). Portanto, neste caso, o valor de retorno é um ponteiro const para um constint
. Fazer o próprio ponteiro não const
faz sentido aqui, pois o valor de retorno não é um lvalue que pode ser modificado. Fazer a ponta const
, entretanto, garante que o chamador não pode modificar o int
(ou array de int
s) retornado por Method3
.
const int*const&
torna-se int const*const&
, portanto, é uma referência a um ponteiro const para um constint
. Passar um ponteiro const por referências masculinas também não faz sentido - você não pode modificar o valor referenciado já que o ponteiro é const
e as referências e ponteiros ocupam armazenamento igual, então não há nenhuma economia de espaço também.
O último const
indica que o método não modifica o this
objeto. O this
ponteiro dentro do corpo do método terá a declaração (teórica) T const * const this
. Isso significa que um const T*
objeto será capaz de chamar T::Method3()
.
const
s no início da frase. É precisamente por isso que acho uma má prática colocar const
lá, embora a linguagem o permita, e é o uso mais comum.
Uma maneira fácil de lembrar as regras do const
é pensar da seguinte maneira: const
aplica-se à coisa à sua esquerda, a menos que não haja nada à sua esquerda.
Portanto, no caso de const int * const
, a primeira const não tem nada à sua esquerda, então ela se aplica a int
e a segunda tem algo à sua esquerda, então ela se aplica ao ponteiro.
Esta regra também informa o que aconteceria no caso de você ter const int const *
. Uma vez que ambos os constantes se aplicam a int
esta expressão, é redundante e, portanto, inválido.
const /* don't modify the int or array of ints' value(s) */
int* const /* as a retval, ignored. useless declaration */
Method3(const /* don't modify the int or array of ints' value(s) */
int* const /* don't modify the pointer's value, the address to which `pointer` points to. e.g. you cannot say `++pointer` */
&) const; /* this method does not modify the instance/object which implements the method */
Eu gosto de usar o método "relógio" ou "espiral" onde, começando com o nome do identificador (neste caso Method3
), você lê da esquerda para a direita e vice-versa, etc. para decodificar convenções de nomenclatura. Portanto, const int* const Method3(const int* const&) const
é um método de classe que não altera nenhum membro da classe (de alguma classe sem nome) e faz uma referência constante a um ponteiro que aponta para uma constante int
e retorna um ponteiro constante para uma constante int
.
Espero que isto ajude,
Jason
Uma maneira fácil de lembrar o const em C ++ é quando você vê algum código na forma de:
XXX const;
const YYY;
XXX, YYY será um componente constante,
XXX const
forma:
function ( def var ) const; ------#1
* const; ------#2
const YYY
Formato:
const int; ------#3
const double;
As pessoas costumam usar esses tipos. Quando você vir em "const&"
algum lugar, não se sinta confuso, const está descrevendo algo antes de si mesmo. portanto, a resposta a esse problema é evidente agora.
const int* const Method3(const int* const&) const;
| | | | |
#3 #2 #3 #2 #1
Eu só quero mencionar que const int* const&
é de fato uma referência constante a const int*
. Por exemplo:
int i = 0;
int j = 1;
int* p = &i;
int* q = &j;
const int* const& cpref = p;
cpref = q; //Error: assignment of read-only reference 'cpref'
É também o caso de int* const&
, O que significa: "Uma referência constante a int*
".
Mas const int*&
é uma referência não constante a const int*
.
Espero que isto ajude.
Ler da direita para a esquerda facilita a compreensão dos modificadores.
Um método const que faz referência a um ponteiro const para um const int chamado Method3
que retorna um ponteiro const para um const int.
mutable
)const # 1: O ponteiro retornado por Method3 se refere a um const int.
const # 2: O valor do ponteiro retornado pela própria função é const. Esta é uma const inútil (embora gramaticalmente válida), porque o valor de retorno de uma função não pode ser um valor l.
const # 3: O tipo de ponteiro passado por referência à função aponta para um const int.
const # 4: O valor do ponteiro passado por referência à função é, ele mesmo, um ponteiro const. Declarar um valor que é passado para uma função como const normalmente seria inútil, mas esse valor é passado por referência, portanto, pode ser significativo.
const # 5: A função (presumivelmente uma função-membro) é const, o que significa que não é permitido (a) atribuir novos valores a qualquer membro do objeto do qual faz parte ou (b) chamar uma função-membro não const sobre o objeto ou qualquer um de seus membros.
const
no final do método está o qualificador, significando que o estado do objeto não será alterado.
const int*const&
significa receber por referência um ponteiro const para uma localização const. Ele não pode mudar para apontar para um local diferente, nem mudar o valor para o qual está apontando.
const int*const
é o valor de retorno que também é um ponteiro constante para um local constante.
Alguns exemplos podem ser bons para demonstrar esse conceito, quanto mais, melhor imho.
class TestClass
{
private:
int iValue;
int* oValuePtr;
int& oValueRef;
public:
int TestClass::ByValMethod1(int Value)
{
// Value can be modified
Value++;
// iValue can be modified
iValue = Value;
iValue += 1;
// Return value can be modified
return ++iValue;
}
int TestClass::ByValMethod2(const int Value)
{
// Value *cannot* be modified
// Variable is const variable
Value++;
// iValue can be modified
iValue = Value;
iValue += 1;
// Return value can be modified
return ++iValue;
}
const int TestClass::ByValMethod3(int Value)
{
// Value can be modified
Value++;
// iValue can be modified
iValue = Value;
iValue += 1;
// Return value can be modified
return ++iValue;
}
const int TestClass::ByValMethod4(const int Value)
{
// Value *cannot* be modified
// Variable is const variable
Value++;
// iValue can be modified
iValue = Value;
iValue += 1;
// Return value can be modified
return ++iValue;
}
const int TestClass::ByValMethod5(const int Value) const
{
// Value *cannot* be modified
// Variable is const variable
Value++;
// iValue *cannot* be modified
// Access through a const object
iValue = Value;
iValue += 1;
// Return value *cannot* be modified
// Access through a const object
return ++iValue;
}
int& TestClass::ByRefMethod1(int& Value)
{
// Value can be modified
Value++;
// oValueRef can be modified
oValueRef = Value;
oValueRef += 1;
// Return value can be modified
return ++oValueRef;
}
int& TestClass::ByRefMethod2(const int& Value)
{
// Value *cannot* be modified
// Variable is const variable
Value++;
// oValueRef can be modified
oValueRef = Value;
oValueRef += 1;
// Return value can be modified
return ++oValueRef;
}
const int& TestClass::ByRefMethod3(int& Value)
{
// Value can be modified
Value++;
// oValueRef can be modified
oValueRef = Value;
oValueRef += 1;
// Return value can be modified
return ++oValueRef;
}
const int& TestClass::ByRefMethod4(const int& Value)
{
// Value *cannot* be modified
// Variable is const variable
Value++;
// oValueRef can be modified
oValueRef = Value;
oValueRef += 1;
// Return value can be modified
return ++oValueRef;
}
const int& TestClass::ByRefMethod5(const int& Value) const
{
// Value *cannot* be modified
// Variable is const variable
Value++;
// oValueRef can be modified
oValueRef = Value;
oValueRef += 1;
// Return value can be modified
return ++oValueRef;
}
int* TestClass::PointerMethod1(int* Value)
{
// Value can be modified
Value++;
// oValuePtr can be assigned
oValuePtr = Value;
// oValuePtr can be modified
oValuePtr += 1;
// Return value can be modified
return ++oValuePtr;
}
int* TestClass::PointerMethod2(const int* Value)
{
// Value can be modified
Value++;
// oValuePtr cannot be assigned
// const int* to int*
oValuePtr = Value;
// oValuePtr can be modified
oValuePtr += 1;
// Return value can be modified
return ++oValuePtr;
}
const int* TestClass::PointerMethod3(int* Value)
{
// Value can be modified
Value++;
// oValuePtr can be assigned
oValuePtr = Value;
// iValue can be modified
oValuePtr += 1;
// Return value can be modified
return ++oValuePtr;
}
const int* TestClass::PointerMethod4(const int* Value)
{
// Value cannot be modified
Value++;
// oValuePtr *cannot* be assigned
// const int* to int*
oValuePtr = Value;
// oValuePtr can be modified
oValuePtr += 1;
// Return value can be modified
return ++oValuePtr;
}
const int* TestClass::PointerMethod5(const int* Value) const
{
// Value can be modified
++Value;
// oValuePtr *cannot* be assigned
// const int* to int* const
// Access through a const object
oValuePtr = Value;
// oValuePtr *cannot* be modified
// Access through a const object
oValuePtr += 1;
// Return value *cannot* be modified
return ++oValuePtr;
}
};
Eu espero que isso ajude!