2009-02-06 12 views
38

Duplicar posibles:
When should you use 'friend' in C++?Cuándo utilizar la clase amigo en C++

me estaba cepillando en mi C++ (soy un desarrollador de Java) y me encontré con la palabra clave friend class que me había olvidado por un tiempo. ¿Es esta una de esas características que forma parte del fregadero de la cocina, o hay una buena razón para hacerlo en lugar de simplemente un captador de vainilla? Entiendo la diferencia en que limita quién puede acceder a los datos, pero no puedo pensar en un escenario cuando sea necesario.

Nota: He visto una pregunta similar, pero específicamente estoy preguntando, ¿es esta una función avanzada que no agrega ningún valor real excepto para confundir a las personas que miran tu código hasta que se den cuenta de lo que estás haciendo ?

+0

Si bien obviamente hay un uso para las clases de amigos, de lo contrario las mentes más grandes de lo que no las habría incluido en la especificación del lenguaje, tiendo a mirarlas como un olor de diseño. En general, me indican que debo volver a mirar la jerarquía de mi clase y, en la mayoría de las ocasiones, generalmente me parece que puedo reestructurarla de manera más elegante y obviar la necesidad de una clase de amigos. – Mawg

Respuesta

40

Estoy de acuerdo con los comentarios que dicen que el amigo de palabras clave puede mejorar la encapsulación si se usa con prudencia. Solo agregaría que el uso más común (¡legítimo!) Para las clases de amigos puede estar probando. Es posible que desee que una clase de prueba tenga un mayor grado de acceso del que tendrían otras clases de clientes. Una clase de prueba podría tener una buena razón para mirar los detalles internos que están deliberadamente ocultos de otras clases.

+0

Good Point John: "Simplemente agregaría que el uso más común (¡legítimo!) Para las clases de amigos puede estar probando" :). – mahesh

+1

Otorgar amistad a las clases anidadas (funtores, iteradores, ...) es la forma más común de usar 'amigo'. Otorgar acceso a las clases relacionadas se debe seguir con precaución (significa acoplamiento ajustado), pero puede estar justificado. Yo también hice la segunda prueba. –

19

En mi experiencia, los casos cuando el amigo (o mutable, que es un poco similar) para mejorar realmente la encapsulación de los datos son poco frecuentes en comparación con qué frecuencia se utiliza para romper la encapsulación.

Rara vez es útil para mí, pero cuando lo uso es para casos en los que he tenido que dividir una clase que anteriormente era una sola clase en dos clases separadas que necesitan acceder a algunos datos/funcionalidades comunes.

Editar para responder a Outlaw comentario del programador: Estamos absolutamente de acuerdo en esto. Otra opción aparte de las clases de amistad después de dividirlas es hacer acceso público, ¡que a veces rompe la encapsulación! Creo que algunas personas piensan que las clases amigas de alguna manera rompen la encapsulación porque la han visto usar inadecuadamente mucho, y muchas personas probablemente nunca ven el código donde se ha usado correctamente, porque es algo raro. Sin embargo, me gusta su forma de decirlo: la amabilidad es un buen término medio entre no permitirle dividir su clase y hacer TODO accesible para el público.

Editar para responder a David Thornley: Estoy de acuerdo en que la flexibilidad que C++ permite hacer cosas como esta es el resultado de las decisiones de diseño que entraron en C++. Creo que eso es lo que hace que sea aún más importante entender qué cosas son generalmente buenas y malas en un lenguaje flexible. La perspectiva de Java es que nunca deberías tener clases de amigos para que no se proporcionen, pero como programadores de C++, es nuestra responsabilidad como comunidad definir el uso apropiado de estos constructos de lenguaje muy flexibles pero a veces mal utilizados.

Editar para responder a Tom: Mutable no necesariamente rompe la encapsulación, pero muchos de los usos de la palabra clave mutable que he visto en situaciones de la vida real rompen la encapsulación, porque es mucho más común ver gente rompiendo la encapsulación con mutable que realmente encontrar y entender un uso adecuado de mutable en primer lugar.

+3

+1 A veces puede que tenga que extraer una nueva clase de una existente para, por ejemplo, problemas de legibilidad, pero aún desea mantener el acoplamiento ajustado. Desea otorgar acceso especial a la nueva clase, pero no desea que estos métodos sean públicos. –

+3

Tenga en cuenta que la filosofía de C++ es proporcionar herramientas potentes y nítidas, y no preocuparse por cómo se usarán mal. Stroustrup explica esto en algún lugar de "Design & Evolution". Es por eso que "amigo" está en C++, y no en Java (que tiene una filosofía diferente). –

+7

¿por qué la encapsulación de ruptura 'mutable'? – Tom

1

miro el constructo friend como una de las características de la lengua que se debe utilizar en raras ocasiones, pero eso no significa que sea inútil. Hay varios patrones que requieren la creación de las clases friend, muchas de ellas ya en este sitio en la barra "Relacionada" a la derecha. ====>

+0

Un buen comentario, pero apenas una respuesta – Mawg

1

Friendship se usa cuando tiene varias clases y/o funciones que trabajan juntas para proporcionar la misma abstracción o interfaz. El ejemplo clásico es implementar algún tipo de clase numérica, y todas las funciones de operador no miembro (*, -, +, < <, etc.) reciben amistad para que puedan trabajar en los datos privados de la clase numérica.

Tales casos de uso son algo raros, pero existen, y amigo es muy útil.

+0

La pregunta era sobre las clases de amigo no otros usos de amigo? –

+1

Es la misma idea. Le das amistad a las funciones o clases si trabajan juntas para proporcionar una abstracción uniforme. –

7

Una instancia concreta sería una fábrica de clases, donde desea que una clase solo se cree a través de otra clase de fábrica, por lo que los constructores serán privados, y la clase de fábrica un amigo de la clase producida.

Es algo así como un zócalo 2 "de 12 puntos y 3/4" - no es muy común, pero cuando lo necesitas, estás muy contento de tenerlo.

+2

Este es un gran punto. Como C++ no tiene paquetes (lo que podría ser una manera de implementar una Factory en C# o Java), parece que tiene que usar un amigo Factory, o tener un constructor protegido, y una clase de implementación hija que se crea por la fábrica. Friend te permite tener una fábrica con menos código en C++. –

2

sección de las preguntas más frecuentes acerca de los amigos: here

sección de la FQA sobre los amigos: here

dos puntos de vista diferentes sobre el amigo.

12

Cuando desee que una clase (Fábrica) sea responsable de crear instancias de otra clase (Tipo). Puede hacer que el constructor del Tipo sea privado y así asegurarse de que solo Factory pueda crear objetos Type. Es útil cuando desea delegar los controles en alguna otra clase que podría servir como un validador. Solo un escenario de uso.

P.S. Realmente me falta la palabra clave "amigo" en C# ...

0

Siempre uso amigo (y solo) para probar métodos privados de prueba. La única otra forma en que me puedo imaginar para hacer esto sería cargar la interfaz pública con un montón de métodos de prueba, lo cual es demasiado complicado, por lo que prefiero ocultar los métodos de prueba en una clase de prueba separada.

Algo como esto:

class cMyClassTest; 

class cMyClass 
{ 
public: 
..... 

private: 
friend cMyClassTest; 
int calc();  // tricky algorithm, test carefully 

}; 

class cMyClassTest 
{ 
public: 
int test_calc() 
{ 
    cMyClass test; 
    .... 
    int result = test.calc(); 

    if(result == 42) 
     return 1; 
    return 0; 
} 
}; 
0

clase friend significa que todos sabemos que es acesss el valor de la variable de otra clase por lo que se utiliza principalmente para el uso de los valores por lo que no hay necesidad de devolver el valor de otra clase a función principal luego principal a función de miembro de clase necesaria pero teniendo el problema que es una clase es amigo para otra clase entonces clase de amigo debería estar debajo de esa clase

1

Aquí hay un ejemplo, de varios, estoy seguro, donde una clase de amigo puede ser legítimamente utilizada sin ignorar los motivos de la encapsulación.

MyClass hereda de GeneralClass. MyClass se ha ampliado, por lo que creó HelperClass para encapsular parte de la función de MyClass. Sin embargo, HelperClass necesita acceso a algunas funciones protegidas en GeneralClass para realizar correctamente su función, por lo que hace de HelperClass un amigo de MyClass.

Esto es mejor que exponer las funciones protegidas, porque no es necesario que estén disponibles para todos, pero ayuda a mantener su código organizado de manera POO para evitar que MyClass se vuelva demasiado complejo. Tiene sentido, porque aunque HelperClass no está concretamente relacionado con MyClass por herencia, sí tiene algún tipo de conexión lógica, incorporada en el código y en el diseño, como "amigo".