Respuestas:
Lea esto: https://isocpp.org/wiki/faq/const-correctness
El final const
significa que la función Method3
no modifica los miembros no mutables de su clase.
const int* const
significa un puntero constante a un int constante: es decir, un puntero que no se puede cambiar, a un int que no se puede cambiar: la única diferencia entre esto y const int&
es que se puedenull
const int* const&
significa una referencia a un puntero constante a una constante int. Por lo general, los punteros no se pasan por referencia; const int* &
tiene más sentido porque significaría que el puntero podría cambiarse durante la llamada al método, que sería la única razón por la que puedo ver pasar un puntero por referencia, const int* const&
es a todos los efectos lo mismo const int* const
excepto que probablemente sea menos eficiente ya que los punteros son tipos de datos antiguos sin formato (POD) y, en general, deberían pasarse por valor.
Es más fácil de entender si lo reescribe como completamente equivalente
// 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;
luego léalo de derecha a izquierda.
# 5 dice que la declaración de función completa a la izquierda es const
, lo que implica que esta es necesariamente una función miembro en lugar de una función libre.
# 4 dice que el puntero a la izquierda es const
(no se puede cambiar para apuntar a una dirección diferente).
# 3 dice que el int
de la izquierda es const
(no se puede cambiar para tener un valor diferente).
# 2 dice que el puntero de la izquierda es const
.
# 1 dice que el int
de la izquierda es const
.
Poniéndolo todo junto, puede leer esto como una const
función miembro nombrada Method3
que toma una referencia a un const
puntero a un int const
(o a const int
, si lo prefiere) y devuelve un const
puntero a un int const
( const int
).
(La nota 2 es completamente superflua ).
En primer lugar const T
es equivalente a T const
.
const int* const
es por tanto equivalente a int const * const
.
Al leer expresiones con muchos const
tokens y punteros, siempre intente leerlos de derecha a izquierda (después de aplicar la transformación anterior). Entonces, en este caso, el valor de retorno es un puntero constante a una constanteint
. Hacer el puntero en sí const
no tiene sentido aquí, ya que el valor de retorno no es un valor l que pueda modificarse. Sin const
embargo, hacer el pointee garantiza que la persona que llama no puede modificar el int
(o la matriz de int
s) devuelto por Method3
.
const int*const&
se convierte en int const*const&
, por lo que es una referencia a un puntero constante a una constanteint
. Pasar un puntero constante por referencias masculinas tampoco tiene sentido: no puede modificar el valor referenciado ya que el puntero es const
y las referencias y los punteros ocupan el mismo almacenamiento, por lo que tampoco hay ahorros de espacio.
El último const
indica que el método no modifica el this
objeto. El this
puntero dentro del cuerpo del método tendrá la declaración (teórica) T const * const this
. Esto significa que un const T*
objeto podrá llamar T::Method3()
.
const
s al principio de la frase. Precisamente por eso creo que es una mala práctica poner const
ahí, aunque el lenguaje lo permita, y es el uso más común.
Una forma fácil de recordar las reglas de const
es pensar en ello de esta manera: se const
aplica a la cosa a su izquierda, a menos que no haya nada a su izquierda.
Entonces, en el caso de const int * const
, la primera constante no tiene nada a su izquierda, por lo que se aplica a int
y la segunda tiene algo a su izquierda, por lo que se aplica al puntero.
Esta regla también le dice lo que sucedería en el caso en que lo haya hecho const int const *
. Dado que ambas const se aplican a int
esta expresión, es redundante y, por lo tanto, inválida.
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 */
Me gusta usar el método de "reloj" o "espiral" en el que a partir del nombre del identificador (en este caso Method3
) se lee de izquierda a derecha, de izquierda a derecha, de atrás a izquierda, etc. para decodificar convenciones de nombres. Por tanto, const int* const Method3(const int* const&) const
es un método de clase que no cambia ningún miembro de clase (de alguna clase sin nombre) y toma una referencia constante a un puntero que apunta a una constante int
y devuelve un puntero constante a una constante int
.
Espero que esto ayude,
Jason
Una forma fácil de recordar la constante en C ++ es cuando ve un código en forma como:
XXX const;
const YYY;
XXX, YYY será un componente constante,
XXX const
forma:
function ( def var ) const; ------#1
* const; ------#2
const YYY
formar:
const int; ------#3
const double;
La gente suele utilizar estos tipos. Cuando vea en "const&"
algún lugar, no se sienta confundido, const está describiendo algo antes de sí mismo. de modo que la respuesta a este problema es evidente ahora.
const int* const Method3(const int* const&) const;
| | | | |
#3 #2 #3 #2 #1
Solo quiero mencionar que de const int* const&
hecho es una referencia constante a const int*
. Por ejemplo:
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'
También es el caso de int* const&
, Lo que significa: "Una referencia constante a int*
".
Pero const int*&
es una referencia no constante a const int*
.
Espero que esto ayude.
Leer de derecha a izquierda facilita la comprensión de los modificadores.
Un método const que toma una referencia a un puntero const a un int const llamado Method3
que devuelve un puntero const a un int const.
mutable
)const # 1: el puntero devuelto por Method3 se refiere a un int const.
const # 2: el valor del puntero devuelto por la función, en sí, es const. Esta es una constante inútil (aunque gramaticalmente válida), porque el valor de retorno de una función no puede ser un valor l.
const # 3: el tipo de puntero pasado por referencia a la función apunta a un const int.
const # 4: El valor del puntero pasado por referencia a la función es, en sí mismo, un puntero constante. Declarar un valor que se pasa a una función como constante normalmente no tendría sentido, pero este valor se pasa por referencia, por lo que puede ser significativo.
const # 5: La función (presumiblemente una función miembro) es constante, lo que significa que no está permitido (a) asignar nuevos valores a ningún miembro del objeto del que forma parte o (b) llamar a una función miembro no constante sobre el objeto o cualquiera de sus miembros.
const
al final del método está el calificador que significa que el estado del objeto no se va a cambiar.
const int*const&
significa recibir por referencia un puntero constante a una ubicación constante. No puede cambiar para apuntar a una ubicación diferente ni cambiar el valor al que apunta.
const int*const
es el valor de retorno que también es un puntero constante a una ubicación constante.
Algunos ejemplos podrían ser buenos para demostrar este concepto, cuanto más mejor en mi humilde opinión.
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;
}
};
¡Espero que esto ayude!