Estoy tratando de entender C ++ amigo. ¿Cuándo es el buen caso de uso para usar amigo? Supongo que si queremos permitir que otra clase tenga acceso a los atributos de otras clases, ¿por qué no lo hacemos público o heredamos de esa clase?
Gracias por tu ayuda.
Respuestas:
Hacer que un miembro de la clase
public
signifique otorgar acceso a todos a ella, rompiendo así la encapsulación por completo.La herencia de una clase a menudo no es deseable, si la clase amiga no está destinada a ser una subclase. Subclasificar solo para acceder a los elementos internos de una clase es un grave error de diseño. E incluso una subclase no puede ver los miembros privados de su clase base.
Un uso típico de
friend
es para operadores que no pueden ser miembros, como operadores de flujo,operator+
etc. En estos casos, la clase real con la que están asociados no es (siempre) el primer parámetro de la función, por lo que la función no puede implementarse como un método miembro.Otro ejemplo es implementar un iterador para una colección. El iterador (y solo el iterador) necesita ver las partes internas de su colección principal, sin embargo, no es una subclase de la colección.
fuente
El ejemplo que he visto con mayor frecuencia para las clases de amigos que se usan en C ++ es en pruebas unitarias. Las pruebas unitarias generalmente quieren saber todo sobre sus partes internas, pero no son parte de usted, y no tiene sentido que intenten heredar de usted.
Si no está familiarizado con la escritura de pruebas unitarias, le sugiero que comience de inmediato.
fuente
Esta pregunta debería estar en stackoverflow. De todos modos, usa un amigo solo cuando desea compartir las partes privadas de su clase con otra clase (o clases) pero no con nadie más. Si los hace públicos, todos pueden ver sus partes privadas (juego de palabras ;-P). Hay dos restricciones importantes que imponen la privacidad: 1) debe especificar quién es su amigo. Nadie más puede ser un amigo. 2) no se puede heredar el comportamiento "amigable" en las subclases de la clase amigo
fuente
Un uso típico es otorgar acceso a funciones que forman parte de la interfaz de la clase, pero gracias a otras reglas realmente no puede ser parte de la clase propiamente dicha. Los insertadores / extractores para iostreams son un ejemplo clásico:
Hacer que estos operadores sean miembros de la clase no funcionará. Una operación de E / S se parece a:
Para un operador implementado como una función miembro, esto se resolvería como:
Es decir, la función debería ser miembro de
std::cout
, no desomething
. Como no queremos modificarstd::ostream
constantemente, nuestra única opción razonable es sobrecargar al operador con una función libre en lugar de una función miembro. Eso nos deja con dos posibilidades: ignorar la encapsulación por completo y hacer que todo en la clase sea público, o mantenerlo privado, pero otorgar acceso a las pocas cosas que realmente lo necesitan.Hacer que otra clase sea amiga es bastante menos común. En este caso, normalmente está creando algo en el orden de un módulo o subsistema: un conjunto de clases que funcionan juntas y tienen cierto grado de acceso especial entre sí que no se otorga al mundo en general.
fuente
Hay un buen ejemplo de la necesidad de clases de amigos en esta solicitud de clases de amigos en C # , un lenguaje que no las tiene.
Cotizado al por mayor aquí:
Mads Torgersen, C # Language PM, incluso ha respondido a esta propuesta, afirmando que siente que la preocupación es realmente válida, pero no está seguro acerca de la implementación específica sugerida allí.
El C ++
friend
es solo una de las formas de abordar el problema descrito.fuente
Cuando quieres que tus clases tengan relaciones monógamas.
Por ejemplo, cuando no desea que clases desconocidas accedan a sus elementos privados, pero sus socios sí necesitan acceso.
fuente
He encontrado que las clases de amigos en C ++ son útiles cuando en Java hubiera utilizado el acceso a paquetes. Es decir, tengo un montón de clases que están tan íntimamente relacionadas que están escritas y mantenidas como una unidad, en los mismos archivos de origen. Cualquiera que trabaje en uno de ellos realmente está trabajando en todos ellos. Los invariantes que mantienen mantienen juntos. Tiene sentido que vean las partes internas del otro para que puedan mantener su invariante compartido.
Lo que no tiene sentido es el acceso protegido. Si no es seguro exponer al público una parte de mis elementos internos, no es seguro exponerlo a lo que sea que aparezca más tarde en un proyecto completamente no relacionado y afirme ser mi subclase. Permitir que las subclases usen mi interfaz pública, como todos los demás. (A menos que sean amigos, pero en ese caso los escribí y los implementé en la misma fuente, por lo que apenas son de otro proyecto).
fuente
Digamos que hay una función externa que requiere que realice operaciones en miembros privados o protegidos de dos clases diferentes dentro de su programa. ahora, para que esa función obtenga acceso y realmente use estos miembros de la clase, debe hacerlo amigo de ambas clases. Teniendo en cuenta que al hacer que sea un amigo de estas dos clases no lo hace miembro de las clases, solo gana el impedimento de referirse a los miembros privados o protegidos de estas clases. Puedo decir que necesitaría usar una función de amigo cuando quiera operar en objetos de dos clases diferentes. Aunque el uso excesivo de la función y clase amigo puede reducir el valor de la encapsulación.
fuente