2011-01-16 8 views
8

En el fragmento de código, puedo acceder a la variable miembro privada fuera del alcance de la clase. Aunque esto nunca debería hacerse, ¿por qué está permitido en este caso? ¿Es una mala práctica recibir una variable privada devuelta por referencia?¿Por qué puedo exponer a miembros privados cuando devuelvo una referencia de una función de miembro público?

#include <iostream> 
#include <cstdlib> 

class foo 
{ 
    int x; 
    public: 
     foo(int a):x(a){} 
     int methodOne() { return x; } 
     int& methodTwo() { return x; } 
}; 

int main() 
{ 
    foo obj(10); 
    int& x = obj.methodTwo(); 
    x = 20;    // With this statement, modifying the state of obj::x 

    std::cout << obj.methodOne(); 
    getchar(); 
    return 0; 
} 

Y respecto a este método, ¿qué transmite el tipo de retorno? Y también, ¿cuándo debería tener un tipo de devolución de este tipo?

int& methodTwo() { return x; } 

PS: Lo siento si la línea de asunto es vago. ¿Alguien puede cambiarlo al contenido relevante aquí? Gracias.

Respuesta

15

private no significa que "esta memoria solo puede ser modificada por funciones miembro" - significa que "los intentos directos de acceder a esta variable darán lugar a un error de compilación". Cuando expone una referencia al objeto, ha expuesto efectivamente el objeto.

¿Es una mala práctica recibir una variable privada devuelta por referencia?

No, depende de lo que desee. Cosas como std::vector<t>::operator[] serían bastante difíciles de implementar si no pudieran devolver una referencia que no sea const :) Si desea devolver una referencia y no desea que los clientes puedan modificarla, simplemente haga una referencia const.

+0

Para las personas que pasan por: [esta pregunta] (http://stackoverflow.com/questions/8005514/is-release-references-of-member-variables-bad-pratice) sugiere que puede ser peligroso devolver una referencia a su miembros de la clase. – Arthur

+0

@Arthur: Sí, como dije, depende de lo que quiera hacer. Funciona muy bien para 'std :: vector', pero hay muchos casos en los que es incorrecto hacerlo también. –

3

La devolución de miembros privados como referencia es perfectamente válida y el programador que escribe una clase es responsable de elegir cuidadosamente si esto debe permitirse. This link da un ejemplo cuando esto se puede hacer.

2

este código:

int& methodTwo() { return x; } 

significa que la función devuelve una referencia a un entero. Al igual que cuando se pasa un valor por referencia a una función, si se cambia el valor de retorno de methodTwo, también lo hace el valor que methodTwo devolvió. En este caso, campo de clase x.

En el código que ha escrito, esto significa que está dejando que la variable privada x escape su alcance (un campo de clase) y se pase por el mundo exterior. Esto sin duda es una mala práctica (porque x se puede cambiar en formas que pueden romper la clase foo, pero sin duda es permisible.

Recuerde público/privado/protegido están en tiempo de compilación única. Una vez que su aplicación se compila, los campos privados se encuentran junto a los campos públicos y no hay protección contra modificaciones. Lo mismo es cierto para lenguajes administrados como C# y Java.

En general, debe evitar el envío de referencias porque hace que sea muy difícil de entender cuando los constructores/destructores get call. Sin embargo, devolver una referencia puede ser más rápido. Si su método devolvió un tipo de estructura que era ENORME, devolviendo una referencia constante a la misma str El tipo de canal solo debería tomar de cuatro a ocho bytes (un puntero a ese objeto). Sin embargo, hay mejores formas de optimizar para este tipo de cosas.

+1

Estoy totalmente en desacuerdo en el punto "debe evitar devolver referencias", dado que el compilador puede eludir llamadas al constructor de copias si devuelve el valor, lo único que gana en muchos casos es volver por el valor es construcciones de depuración lentas (porque el compilador realiza RVO/NRVO sobre usted en modo de lanzamiento). –

+1

Al no ser un usuario de C++ a nivel de gurú, me reservo el derecho de estar equivocado :) ¿Pero no obtendrá un comportamiento indefinido si devuelve una referencia a una variable local? (Es decir, ¿le queda un puntero a algún lugar al azar en la pila?) –

+0

Eso es correcto. Intentar acceder a una variable destruida a través de una referencia da como resultado un comportamiento indefinido. Pero para cosas como getters de clase que regresan por referencia es el comportamiento normal y esperado. –

0

Como dijo Donotalo, es perfectamente válido.La idea de tener miembros privados es deshabilitar otras clases/funciones para acceder al miembro privado de la clase sin su permiso. Si usted está dispuesto a hacer una función para permitir que otras clases/funciones para acceder a sus miembros privados, el compilador no tiene nada en contra de que realmente :-)

Por lo general, es útil tener un miembro privado y tener un obtener función para permitir que otras clases/funciones obtengan el valor de la función, pero solo la clase podrá cambiarla.

-1

estoy en condiciones de acceder a la variable miembro privada fuera del ámbito de la clase

Si se refiere a la x en main() continuación, que es diferente de la declarada en xclass foo. Si intenta acceder al obj.x, el compilador definitivamente se quejará.

¿Es una mala práctica recibir una variable privada devuelta por referencia?

No hay nada de malo en "recibir" la referencia a un miembro privado. Pero dar la referencia a un miembro privado hace que declararlo privado inútil. Al declarar que una variable es un miembro privado, restringe el acceso a ese miembro solo a los métodos de la clase.

con respecto a este método, ¿qué indica el tipo de devolución? Y también, ¿cuándo debería tener un tipo de devolución de este tipo?

¿No está seguro del método al que se refiere?!?!?!

+2

¿De verdad? Lo hace inútil? ¿Cómo se explica 'std :: vector :: operator []' then? Cualquier puntero de búfer que el vector está utilizando no está expuesto al mundo, pero los datos son (y deberían ser, dado el punto del vector) –

+0

@Billy O'Neal: Buen punto. Gracias por mencionarlo. – yasouser

Cuestiones relacionadas