2011-02-10 27 views
15
class Foo 
{ 
    int Bar; 

    public: 

    int& GetBar() const 
    { 
     return Bar; 
    } 
} 

¿es correcto que GetBar es un método const? En realidad, no está cambiando nada, pero está proporcionando al "mundo exterior" un medio para cambiarlo.Métodos Const que Volver Referencias

+0

Creo que ya ha contestado a su pregunta. Además, en el ejemplo Bar ya es público. – XAder

+0

'& Bar' tiene el tipo' const int * ', no' int & '. Tu compilador debería decirte que esto no está bien. –

+0

¿Has probado compilar? ¿Qué te dijo el compilador? –

Respuesta

18

Usted tiene un error en su código, esto es lo que probablemente significaba:

class Foo 
{ 
    int Bar; 

    public: 

    int& GetBar() const 
    { 
     return Bar; // Removed the ampersand, because a reference is returned, not an address 
    } 
} 

Y no, esto no es legal .Al etiquetar un método con const, no sólo se le aseguras que no toque ninguna de estado interno del objeto, también promete que no volverá a cualquier cosa que se puede utilizar para cambiar el estado del objeto. Una referencia no const puede usarse para modificar el valor de Bar fuera del alcance de GetBar(), por lo tanto, está implicando que no puede mantener la promesa.

Debe cambiar el método para que no sea const, devolver una referencia const, o hacer Bar exento de la promesa marcándolo como mutable. Ej .: mutable int Bar; La palabra clave mutable le dice al compilador que el constness lógica del objeto no depende del estado de Bar. Entonces puedes hacer lo que quieras con él.

4

No, ya que no puede hacer la siguiente asignación: const int x; int &y = x;

Lo que se puede hacer sin embargo es const int x; const int &y = x;

Y, por supuesto, no hay ningún problema en la sobrecarga del método y la creación tanto const y no constante variantes.

3

Probablemente desee devolver Bar, no &Bar. De todos modos, se me cayó este código en Comeau:

class Foo 
{ 
    int Bar; 

    public: 

    int& GetBar() const 
    { 
     return &Bar; 
    } 
}; 

int main(int argc, char** argv) 
{ 
    Foo x; 
    int y = x.GetBar(); 
    y = 5; 
    return 0; 
} 

y consiguió el error:

line 9: error: qualifiers dropped in binding reference of type 
      "int &" to initializer of type "const int" 
      return Bar; 
       ^
1

En primer lugar, para devolver una referencia que no es necesario utilizar el operador de signo en el objeto referenciado ; es necesario si desea obtener un puntero . Entonces, supongo que querías escribir return Bar;.

Entonces, no, no puedes hacer eso; en un método const usted tiene un puntero constthis (en su caso sería un const Foo *), lo que significa que cualquier referencia que pueda llegar a sus campos será una referencia const, ya que usted está accediendo a ellos a través de un " const ruta ".

Por lo tanto, si usted trata de hacer lo que hizo en ese código que obtendrá un error de compilación, ya que estaría tratando de inicializar un (el valor devuelto por el método) int & con un const int & (la referencia se obtener de Bar), que obviamente está prohibido.

g ++ realidad dice:

testconstref.cpp: In member function ‘int& Foo::GetBar() const’: 
testconstref.cpp:9: error: invalid initialization of non-const reference of type ‘int&’ from a temporary of type ‘const int*’ 

que es lo que acabo de decir. :)

Si, en cambio, devuelve una referencia const a un campo de clase de un método const, no tendrá ningún problema.


  1. campos marcados como Excluyendo mutable, que le dice al compilador que tales campos son modificables incluso desde const métodos; esta excepción se ha introducido para permitir que los métodos const cambien el estado "real" del objeto en los casos en que esto no altere su estado "lógico"; Esto puede ser útil para poner en práctica la evaluación perezosa, recuento de referencias, ...
0

const modificador a una función miembro no permite cambiar el estado del objeto con en el mismo de alcance. El compilador simplemente verifica si esta función está modificando el estado del objeto o no en su alcance. Tomando otro ejemplo -

class foo 
{ 
    int num ; 
    public : 
     foo(int anum) 
     { 
      anum = 10; 
     } 
     int getNum() 
     { 
      return num; 
     } 
}; 

foo obj; 
int& myNum = obj.getNum() ; // myNum is just an alias to the private class variable num 
myNum = 40; // Actually changes the content of the private variable. 

Por lo tanto, el compilador simplemente comprueba especificadores de acceso (es decir, si esta variable es accesible o no en este ámbito), pero no acerca de la ubicación de memoria del/public/de variable privada protegida si es devuelto a alguna otra variable .

1

Los miembros de la clase se consideran const cuando se está en un método const. Así que, aunque es Barint dentro de su clase y no const int, en el contexto de GetBar() const es "const int". Por lo tanto devolverlo como referencia o puntero no constante es tan ilegal como hacer:

const int y = 57; int& z = y;

Esto rompe const-corrección a pesar de que la segunda línea en realidad no ha cambiado nada (todavía) en y.

Tenga en cuenta que si su clase tiene miembros de puntero, lo único que es const son los punteros y no lo que señalan. (A menudo se refiere como constness "superficial")

Así, este sería legal:

class A 
{ 
    Foo * foo; 

    public: 
    Foo * getFoo() const // legal. does not have to return const Foo * 
    { 
     return foo; 
    } 
}; 

Tenga en cuenta que en su código original se le permitirá volver Bar por referencia no constante si fuera mutable, porque esos miembros no están limitados por la consistencia de las funciones de los miembros.

Cuestiones relacionadas