¿Por qué la amistad no es al menos opcionalmente heredable en C ++? Entiendo que la transitividad y la reflexividad están prohibidas por razones obvias (digo esto solo para evitar respuestas simples de citas de preguntas frecuentes), pero la falta de algo en la línea de virtual friend class Foo;
me desconcierta. ¿Alguien conoce los antecedentes históricos detrás de esta decisión? ¿Era la amistad realmente solo un truco limitado que desde entonces se ha abierto camino en algunos usos respetables oscuros?
Edite para aclarar: estoy hablando del siguiente escenario, no donde los hijos de A están expuestos a B o tanto a B como a sus hijos. También puedo imaginar la posibilidad de otorgar acceso a anulaciones de funciones de amigos, etc.
class A {
int x;
friend class B;
};
class B {
// OK as per friend declaration above.
void foo(A& a, int n) { a.x = n; }
};
class D : public B { /* can't get in A w/o 'friend class D' declaration. */ };
Respuesta aceptada: como dice Loki , el efecto se puede simular más o menos haciendo funciones proxy protegidas en clases base amigas, por lo que no hay una necesidad estricta de otorgar amistad a una jerarquía de clase o método virtual. No me gusta la necesidad de proxies repetitivos (en los que la base amiga se convierte efectivamente), pero supongo que esto se consideró preferible a un mecanismo de lenguaje que probablemente sería mal utilizado la mayor parte del tiempo. Creo que probablemente es hora de que compre y lea The Design and Evolution of C ++ de Stroupstrup , que he visto recomendar a suficientes personas aquí, para obtener una mejor comprensión de este tipo de preguntas ...
Creo que la respuesta a tu primera pregunta está en esta pregunta: "¿Los amigos de tu padre tienen acceso a tus partes privadas?"
fuente
Una clase amiga puede exponer a su amigo a través de funciones de acceso y luego otorgar acceso a través de ellas.
Esto permite un control más fino que la transitividad opcional. Por ejemplo,
get_cash
puede serprotected
o puede imponer un protocolo de acceso limitado en tiempo de ejecución.fuente
;)
Estándar C ++, sección 11.4 / 8
Si se heredara la amistad, entonces una clase que no estaba destinada a ser un amigo de repente tendría acceso a los aspectos internos de su clase y eso violaría la encapsulación.
fuente
Porque es simplemente innecesario.
El uso de la
friend
palabra clave es en sí mismo sospechoso. En términos de acoplamiento, es la peor relación (muy por delante de la herencia y la composición).Cualquier cambio en el interior de una clase tiene el riesgo de afectar a los amigos de esta clase ... ¿de verdad quieres un número desconocido de amigos? Ni siquiera podrías enumerarlos si quienes heredan de ellos pudieran ser amigos también, y corres el riesgo de romper el código de tus clientes cada vez, seguramente esto no es deseable.
Admito libremente que para los proyectos de tareas o mascotas, la dependencia es a menudo una consideración lejana. En proyectos de pequeño tamaño, no importa. Pero tan pronto como varias personas trabajen en el mismo proyecto y este se convierta en decenas de miles de líneas, deberá limitar el impacto de los cambios.
Esto trae una regla muy simple:
Cambiar las partes internas de una clase solo debería afectar a la clase misma
Por supuesto, probablemente afectará a sus amigos, pero aquí hay dos casos:
std::ostream& operator<<(...)
aquí, que no es un miembro simplemente por accidente de las reglas del idiomaRecomendaría el uso del método simple:
Este
Key
patrón simple le permite declarar a un amigo (de alguna manera) sin realmente darle acceso a sus partes internas, aislándolo de los cambios. Además, le permite a este amigo prestar su llave a los fideicomisarios (como niños) si es necesario.fuente
Una suposición: si una clase declara alguna otra clase / función como amiga, es porque esa segunda entidad necesita acceso privilegiado a la primera. ¿De qué sirve conceder acceso privilegiado a la segunda entidad a un número arbitrario de clases derivadas de la primera?
fuente
B
A
Una clase derivada puede heredar solo algo, que es 'miembro' de la base. Una declaración de amistad no es un miembro de la clase de amistad.
y además
Dado que el 'amigo' no es miembro de la clase base en primer lugar, ¿cómo puede ser heredado por la clase derivada?
fuente
La función de amigo en una clase asigna la propiedad extern a la función. es decir, extern significa que la función ha sido declarada y definida en algún lugar fuera de la clase.
Por lo tanto, significa que la función de amigo no es miembro de una clase. Entonces, la herencia solo te permite heredar las propiedades de una clase, no cosas externas. Y también si se permite la herencia para funciones de amigos, entonces una clase de terceros hereda.
fuente
Friend es bueno en herencia como interfaz de estilo para contenedor Pero para mí, como los primeros dicen, C ++ carece de la herencia propagable
Para mí, el problema de C ++ es la falta de una granularidad muy buena para controlar todos los accesos desde cualquier lugar para cualquier cosa:
Friend Thing puede convertirse en friend Thing. * para otorgar acceso a todos los hijos de Thing
Y más, amigo [área con nombre] Cosa. * Para otorgar acceso a una ubicación precisa en la clase Contenedor a través del área con nombre especial para el amigo.
Ok, detén el sueño. Pero ahora, conoces un uso interesante de amigo.
En otro orden, también puede resultar interesante saber que todas las clases son amistosas consigo mismas. En otras palabras, una instancia de clase puede llamar a todos los
miembros de otra instancia del mismo nombre sin restricción:
fuente
Lógica simple: 'Tengo una amiga Jane. El hecho de que nos hiciéramos amigos ayer no hace que todos sus amigos sean míos.
Todavía necesito aprobar esas amistades individuales, y el nivel de confianza sería el correspondiente.
fuente