2010-10-08 29 views
26

Pido disculpas si esto se ha preguntado, pero ¿cómo creo una función miembro en C++ que devuelve un puntero en los siguientes escenarios: 1. El puntero devuelto es constante, pero la basura dentro puede ser modificada. 2. La basura dentro es constante pero el puntero devuelto se puede modificar. 3. Ni la basura, ni el puntero se pueden modificar.C++ función de miembro const que devuelve un puntero const .. Pero, ¿qué tipo de const es el puntero devuelto?

¿Es así:

  1. int *const func() const
  2. const int* func() const
  3. const int * const func() const

todos los tutoriales que he leído no cubra esta distinción.

Nota al margen: Si mi método es declarado const, los tutoriales dicen que estoy diciendo que no modificaré los parámetros ... Pero esto no es lo suficientemente claro para mí en el caso de que un parámetro sea un puntero . ¿Mis parámetros deben ser como:

a. void func(const int* const x) const;
b. void func(const int* x) const;
c. void func(const int* const x) const;

+0

dado cuenta de que funcs métodos constantes no tienen nada que ver con la modificación de parámetros, pero más acerca de cómo modificar las variables de clase. – Jor

Respuesta

53

no sé qué libro que ha leído, pero si se marca una const método Significa que this será de tipo const MyClass* en lugar de MyClass*, que a su vez significa que no se puede cambiar los miembros de datos estáticos que son no declarado mutable, ni puede llamar a ningún método no const en this.

Ahora para el valor de retorno.

1. int * const func() const

La función es constante y el puntero devuelto es constante, pero puede modificarse la "basura dentro". Sin embargo, no veo sentido devolver un puntero const porque la llamada de función final será un valor r, y los valores r de tipo no de clase no pueden ser const, lo que significa que const se ignorará de todas formas

2. const int* func() const

Esto es útil. La "basura dentro" no se puede modificar

3. const int * const func() const

semánticamente casi lo mismo que 2, debido a razones de 1.

HTH

+1

Creo que tiene un par de datos útiles en esta respuesta, pero mi pregunta aún permanece. Si configuro un método miembro, ¿qué es lo * requerido * que tengo como firma de mi método? Me disculpo si no te entiendo. – Jor

+1

@Jor: No estás _required_ para hacer ninguna restricción sobre el resto de la firma de la función. Lo único a tener en cuenta es que en un método 'const'' this' es un puntero a 'const', por lo que si devuelve un miembro por puntero o referencia, el valor de retorno debería ser referencia o puntero a un tipo' const' o tendrías que hacer un 'const_cast' potencialmente peligroso. –

+1

@Jor: Lo que significa que el tipo de devolución depende de lo que devuelve. Si está devolviendo la dirección de un miembro de la clase, entonces ese miembro está const dentro de una función miembro miembro, por lo que querrá la opción (2). –

9

Algunos usos de const en realidad no tiene mucho sentido.

Suponga que tiene la siguiente función:

void myFunction (const int value); 

La const le dice al compilador que el valor no debe cambiar dentro de la función. Esta información no tiene ningún valor para la persona que llama.Depende de la función en sí decidir qué hacer con el valor. Para la persona que llama, las siguientes dos definiciones de funciones se comportan exactamente lo mismo por él:

void myFunction (const int value); 
void myFunction (int value); 

Puesto que el valor se pasa por valor, lo que significa que la función obtiene una copia local de todos modos.

Por otro lado, si el argumento es una referencia o un puntero, las cosas se vuelven muy diferentes.

void myFunction (const MyClass &value); 

Esto le dice a la persona que llama que el valor se pasa por referencia (por lo que detrás de las pantallas en realidad es un puntero), pero la persona que llama se compromete a no cambiar el valor. Lo mismo es cierto para los punteros:

void myFunction (const MyClass *value); 

Se pasa un puntero a MiClase (debido a razones de rendimiento), pero la función se compromete a no cambiar el valor.

Si queremos escribir lo siguiente:

void myFunction (MyClass * const value); 

Entonces estamos de vuelta int primera situación. myFunction obtiene un puntero, que se pasa por valor y que es const. Como MyFunction obtiene una copia del valor del puntero, no importa para quien llama si es const o no. Lo más importante es que myFunction puede cambiar el contenido del valor, porque la variable del puntero en sí es const, pero el contenido no es.

Lo mismo es cierto para los valores de retorno:

const double squareRoot(double d); 

Esto no tiene ningún sentido. squareRoot devuelve una doble const pero como esto se pasa 'por valor', y por lo tanto necesita ser copiado a mi propia variable local, puedo hacer lo que quiera con ella.

Por otro lado:

const Customer *getCustomer(char *name); 

me dice que GetCustomer me devuelve un puntero a un cliente, y no se me permite cambiar el contenido del cliente.

En realidad, sería mejor hacer la const char-puntero-contenidos, así, ya no espero que la función para cambiar la cadena dada:

const Customer *getCustomer(const char *name); 
+0

Está bien, estoy empezando a entender a Patrick, y me di cuenta de que un método const tiene que ver con no modificar a los miembros de la clase. Así que olvídalo. Pero me gusta su respuesta, así que quizás pueda responderlas: en "const Customer * getCustomer (char * name);" dijiste que la persona que llama no puede modificar el resultado. ¿Pero es el caso que no pueden modificar el resultado a través de la variable devuelta, pero si copian ese puntero a otro puntero, * pueden * modificar los contenidos? – Jor

+0

Y aquí hay otra pregunta. Un método const no puede devolver un puntero a los miembros de su clase a menos que sea un puntero constante. Pero, ¿qué tipo de puntero const debe ser? 1: const * int 2: const * const int 3: int * const – Jor

+0

Si asigna el valor de retorno de la función "const Customer * getCustomer()" a una variable "Customer *", entonces podrá cambiar el contenidos del Cliente. Sin embargo, el compilador C++ da un error en esta asignación, ya que normalmente no se le permite asignar un puntero const a un puntero no const, ya que esto le otorga 'derechos adicionales' (a saber: poder cambiar los contenidos de Cliente). Sin embargo, en algunos casos (especialmente cuando se trata de un código C antiguo más puro), puede que tenga que evitar esto, y luego debe usar un const_cast. – Patrick

0

El método const le impide modificar los miembros. En el caso de los punteros, esto significa que no puede reasignar el puntero. Puede modificar el objeto apuntado por el puntero al deseo de su corazón.

Como el puntero se devuelve por valor (una copia), la persona que llama no puede usarlo para modificar el miembro del puntero de la clase. Por lo tanto, agregar const al valor de retorno no agrega nada.

Las cosas son diferentes si devuelve una referencia al puntero. Ahora, si el puntero no fuera const, esto significaría que una función que no tiene derechos para modificar un valor le está otorgando este derecho a la persona que llama.

Ejemplo:

class X 
{ 
    int* p; 
public: 
    int* get_copy_of_pointer() const //the returned value is a copy of this->p 
    { 
     *p = 42; //this being const doesn't mean that you can't modify the pointee 
     //p = 0; //it means you can't modify the pointer's value 
     return p; 
    } 
    int* const& get_reference_to_pointer() const //can't return a reference to non-const pointer 
    { 
     return p; 
    } 
}; 
1

Devolver un puntero a const tiene mucho sentido, pero que devuelve un puntero constante (no se puede modificar) generalmente no añade valor (aunque algunos dicen que puede evitar los errores del usuario o añadir compilador mejoramiento).

Esto se debe a que el valor de retorno pertenece a la persona que llama de la función, es decir, es su propia copia, por lo que no importa si la modifican (para señalar otra cosa). Sin embargo, el contenido no "pertenece" a la persona que llama y el implementador de la función puede hacer un contrato que es información de solo lectura.

Las funciones de los miembros de Const prometen no cambiar el estado de la clase, aunque esto no es necesariamente aplicado por el compilador. No me refiero aquí a los miembros const_cast o mutable sino al hecho de que si su clase contiene punteros o referencias, una función de miembro constante convierte sus punteros en punteros constantes pero no los convierte en punteros para const, de manera similar sus referencias no se convierten en referencias-a-const. Si estos son componentes de su clase (y dichos componentes a menudo están representados por punteros), sus funciones pueden cambiar su estado.

Los miembros mutables están ahí para permitir que su clase los cambie sin cambiar el estado interno. Por lo general, se pueden aplicar a:

  • Mutex que desea bloquear incluso para leer.
  • Datos que están cargados de forma diferida, es decir, rellenos la primera vez que se accede a ellos.
  • Objetos contados de referencia: Desea aumentar el recuento de referencias si tiene otro visor, por lo tanto, puede modificar su estado solo para leerlo.

const_cast generalmente se considera un "hackeo" y con frecuencia se realiza cuando alguien más no ha escrito su código correctamente const-correct. Puede tener valor, aunque en las siguientes situaciones:

  • múltiples sobrecargas donde uno es const y uno no constante y const Devuelve una constante referencia y la no-const Devuelve una referencia no const, pero por lo demás ellos son lo mismo. Duplicar el código (si no es un simple miembro de datos) no es una gran idea, así que implemente uno en términos del otro y use const_cast para moverse por el compilador.

  • Donde desee en particular llamar a la sobrecarga const pero tener una referencia no const. Equípelo para const primero.

4

int *const func() const

No se puede observar la const aquí a excepción de algunos casos

  • tomar la dirección de func.
  • En C++ 0x, llamando directamente a func con la sintaxis de función-llamada como operando decltype, obtendrá int * const.

Esto se debe a que devuelve un valor de puntero puro, es decir, un valor de puntero que en realidad no está almacenado en una variable de puntero.Tales valores no están consti- tuidos porque no se pueden cambiar de todos modos. No puede decir obj.func() = NULL; aunque le quite el const. En ambos casos, la expresión obj.func() tiene el tipo int* y no es modificable (alguien pronto citará el Estándar y obtendrá el término "valor r").

De modo que en los contextos en los que utilice el valor de retorno no podrá ver la diferencia. En el caso de que se refiera a la declaración o a la función completa, notará la diferencia.

const int* func() const

Esto es lo que normalmente haría si el cuerpo sería algo así como return &this->intmember;. No permite cambiar el miembro int haciendo *obj.func() = 42;.

const int * const func() const

Esto es sólo la combinación de los dos primeros :)

Cuestiones relacionadas