friendship and c++ friend

friendship and inheritance c++



Permitir que una clase de "amigos" acceda solo a algunos miembros privados (7)

Supongamos que tengo tres clases de C ++ FooA, FooB y FooC.

FooA tiene una función miembro llamada Hello , quiero llamar a esta función en la clase FooB, pero no quiero que la clase FooC pueda llamarlo. La mejor manera de darme cuenta de esto es declarar a FooB como una clase amiga de FooA. Pero mientras lo haga, todos los miembros privados y protegidos de FooA estarán expuestos, lo que es bastante inaceptable para mí.

Entonces, quiero saber si hay algún mecanismo en C ++ (03 u 11) mejor que la clase de friend que pueda resolver este dilema.

Y supongo que será bueno si la siguiente sintaxis es posible:

class FooA { private friend class FooB: void Hello(); void Hello2(); private: void Hello3(); int m_iData; }; class FooB { void fun() { FooA objA; objA.Hello() // right objA.Hello2() // right objA.Hello3() // compile error ojbA.m_iData = 0; // compile error } }; class FooC { void fun() { FooA objA; objA.Hello() // compile error objA.Hello2() // compile error objA.Hello3() // compile error ojbA.m_iData = 0; // compile error } };


Creo que puedes usar Attorney-Client aquí.

En tu caso el ejemplo debería ser así.

class FooA { private: void Hello(); void Hello2(); void Hello3(); int m_iData; friend class Client; }; class Client { private: static void Hello(FooA& obj) { obj.Hello(); } static void Hello2(FooA& obj) { obj.Hello2(); } friend class FooB; }; class FooB { void fun() { FooA objA; Client::Hello(objA); // right Client::Hello2(objA); // right //objA.Hello3() // compile error //ojbA.m_iData = 0; // compile error } }; class FooC { void fun() { /*FooA objA; objA.Hello() // compile error objA.Hello2() // compile error objA.Hello3() // compile error ojbA.m_iData = 0; // compile error*/ } };


La solución más segura es usar otra clase como el "intermediario" para tus dos clases, en lugar de hacer que una de ellas sea un friend. Una forma de hacer esto se sugiere en la respuesta de @ForEveR, pero también puede hacer una búsqueda sobre las clases de proxy y otros patrones de diseño que pueden aplicarse.


Necesitarás herencia. Prueba esto:

// _ClassA.h class _ClassA { friend class ClassA; private: //all your private methods here, accessible only from ClassA and _ClassA. } // ClassA.h class ClassA: _ClassA { friend class ClassB; private: //all_your_methods }

De esta manera usted tiene: ClassB es el único que puede usar ClassA . ClassB no puede acceder a los métodos _ClassA , que son privados.



No, y esto no es realmente una limitación. En mi opinión, la limitación es que el friend , en primer lugar, es un arma contundente para eliminar los defectos del diseño.

Su clase FooA no tiene por FooB saber sobre FooB y FooC y "cuál debería poder usarlo". Debe tener una interfaz pública, y no importa quién puede usarla. ¡Ese es el punto de la interfaz! Las funciones de llamada dentro de esa interfaz siempre deben dejar al FooA en un estado agradable, seguro, feliz y consistente.

Y si su preocupación es que podría usar accidentalmente la interfaz FooA de algún lugar al que no quería, bueno, simplemente no haga eso; C ++ no es un lenguaje adecuado para protegerse contra este tipo de errores de usuario. Su cobertura de prueba debería ser suficiente en este caso.

Estrictamente hablando, estoy seguro de que puede obtener la funcionalidad que busca con un "patrón de diseño" extremadamente complicado pero, honestamente, no me molestaría.

Si este es un problema para la semántica del diseño de su programa, le sugiero educadamente que su diseño tiene una falla.


Puede exponer parcialmente las interfaces de una clase a un cliente específico al heredarlo de una clase de interfaz.

class FooA_for_FooB { public: virtual void Hello() = 0; virtual void Hello2() = 0; }; class FooA : public FooA_for_FooB { private: /* make them private */ void Hello() override; void Hello2() override; private: void Hello3(); int m_iData; }; class FooB { void fun() { FooA objA; FooA_for_FooB &r = objA; r.Hello() // right r.Hello2() // right objA.Hello3() // compile error objA.m_iData = 0; // compile error } }; class FooC { void fun() { FooA objA; objA.Hello() // compile error objA.Hello2() // compile error objA.Hello3() // compile error objA.m_iData = 0; // compile error } };

Aquí el control de acceso es mejorado por la clase base FooA_for_FooB . Mediante una referencia de tipo FooA_for_FooB , FooB puede acceder a los miembros definidos dentro de FooA_for_FooB . Sin embargo, FooC no puede acceder a esos miembros ya que se han FooA como miembros privados en FooA . Su propósito se puede lograr al no usar el tipo FooA_for_FooB dentro de FooC , o en cualquier otro lugar, excepto FooB , que puede mantenerse sin prestar mucha atención.

Este enfoque no necesita ningún friend , simplificando las cosas.

Se puede hacer algo similar haciendo que todo sea privado en una clase base, y envolver y exponer selectivamente a algunos de los miembros como público en la clase derivada. Sin embargo, este enfoque a veces puede requerir un desagradable abatimiento. (Porque la clase base se convertirá en la "moneda" de todo el programa).


Toda la idea de un friend es exponer su clase a un amigo.

Hay 2 formas en que podría ser más específico sobre lo que expone:

  1. Heredar de FooA , de esa manera solo se exponen los métodos protegidos y públicos.

  2. Solo hazte amigo de cierto método, de esa manera solo ese método tendrá acceso:

.

friend void FooB::fun();