Explicación del uso de C ++ Const


97
const int* const Method3(const int* const&) const;

¿Alguien puede explicar el uso de cada una de las constantes?


27
Realmente me gusta este método para descifrar declaraciones complicadas: c-faq.com/decl/spiral.anderson.html
Jason

Respuestas:


77

Lea esto: https://isocpp.org/wiki/faq/const-correctness

El final constsignifica que la función Method3no modifica los miembros no mutables de su clase.

const int* constsignifica 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* constexcepto 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.


103

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 intde 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 intde la izquierda es const.

Poniéndolo todo junto, puede leer esto como una constfunción miembro nombrada Method3que toma una referencia a un constpuntero a un int const(o a const int, si lo prefiere) y devuelve un constpuntero a un int const( const int).

(La nota 2 es completamente superflua ).


22

En primer lugar const Tes equivalente a T const.

const int* constes por tanto equivalente a int const * const.

Al leer expresiones con muchos consttokens 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í constno tiene sentido aquí, ya que el valor de retorno no es un valor l que pueda modificarse. Sin constembargo, hacer el pointee garantiza que la persona que llama no puede modificar el int(o la matriz de ints) 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 consty las referencias y los punteros ocupan el mismo almacenamiento, por lo que tampoco hay ahorros de espacio.

El último constindica que el método no modifica el thisobjeto. El thispuntero 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().


2
Votar a favor de esto (y la respuesta similar de ildjarn), en parte por dejar claro que todo tiene más sentido si no pones las primeras consts al principio de la frase. Precisamente por eso creo que es una mala práctica poner constahí, aunque el lenguaje lo permita, y es el uso más común.
TED

12

Una forma fácil de recordar las reglas de constes pensar en ello de esta manera: se constaplica 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 inty 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 intesta expresión, es redundante y, por lo tanto, inválida.


3
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 */

3

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&) constes 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 inty devuelve un puntero constante a una constante int.

Espero que esto ayude,

Jason


2

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 constforma:

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

2

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.


1

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 Method3que devuelve un puntero const a un int const.

  1. Un método const no puede modificar miembros (a menos que lo hagan explícitamente mutable)
  2. Un puntero constante no se puede cambiar para que apunte a otra cosa
  3. Un const int (o cualquier otro tipo) no se puede modificar

1

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.


0
  • 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.


0

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!

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.