2012-06-15 20 views
5

Supongamos que tenemos dos clases:¿Cómo hacer que una clase pueda acceder solo a ciertos miembros privados de otra clase?

class Base 
{ 
private: 
    int x; 
public: 
    void f(); 
}; 

class Foo 
{ 
    // some variables and methods 
}; 

Ahora todo el mundo puede llamar Base::f(), pero quiero solamente Foo para poder hacerlo.

Para lograr este efecto, podemos hacer Base::f() privada y declarar Foo como amigo:

class Base 
{ 
private: 
    int x; 
    void f(); 
    friend Foo; 
}; 

El problema con este enfoque es que Foo tiene el acceso tanto a Base::f() y Base::x (e incluso a cualquier otro miembro privado de Base). Pero quiero que Foo tenga acceso solo al Base::f().

¿Hay alguna manera para que una clase (o una función) otorgue acceso solo a ciertos miembros privados de otra clase? O tal vez alguien podría sugerir un mejor enfoque para mi problema?

EDIT:

Voy a tratar de especificar la restricción de acceso que necesito. En primer lugar, Base es una interfaz en una biblioteca (de hecho, es una clase abstracta). El usuario usa solo las clases derivadas de Base. Base::f() se llama solo por Foo que es otra clase en la biblioteca. Escondido Base::f() del usuario es importante, porque solo Foo sabe cuándo llamarlo. Al mismo tiempo, Foo no debe ensuciar a los demás miembros de Base.

+0

Usted podría hacer 'f()' protegido y usar herencia protegida, creo. – chris

+0

Pero 'Foo' no se deriva de' Base'. – miloszmaki

+0

Fue solo un pensamiento. Tendrás que derivarlo. Después de ver la respuesta 'BaseData', me gustaría ir con eso, sin embargo. – chris

Respuesta

6

Muy hacky, pero esto permitirá un acceso de grano muy fino.

class Base 
{ 
private: 
    int x; 
    void f(); 
    friend class Base_f_Accessor; 
}; 

class Base_f_Accessor 
{ 
private: 
    static void f(Base & b) { b.f(); } 
    friend class Foo; 
} 

class Foo 
{ 
    // some variables and methods 
}; 
+0

Me gusta este enfoque, ya que permite ocultar los detalles de implementación de 'Base_f_Accessor' en un archivo .cpp. De esta manera, 'Foo' también se puede definir en el archivo .cpp y no expuesto al usuario. – miloszmaki

4

Puede crear otra clase que contiene los datos para Base así:

class BaseData { 
protected: 
    int x; 
}; 

class Base : public BaseData { 
    friend class Foo; 
    void f(); 
}; 

Ahora, Foo puede acceder f como método de Base como usted quería, pero no x. La amistad no es conmutativa. Al utilizar protected, x aparece privado para todos, excepto los que derivan directamente del BaseData.

Un mejor enfoque podría ser el uso de la herencia múltiple para definir Base, y proporcionar Foo acceso sólo a aquellas clases que desee desde la cual se deriva Base.

class With_f { 
    friend class Foo; 
protected: 
    virtual void f() = 0; 
}; 

class With_g { 
protected: 
    virtual void g() = 0; 
}; 

class Base : public With_f, public With_g { 
    int x; 
    void f() {} 
    void g() {} 
}; 

Aquí, Foo tendría que tener un puntero a With_fBase, pero podría entonces acceder al método f. Foo no pudo acceder al g.

+0

¿Qué pasaría si hicieras 'Base' un amigo de' BaseData'? ¿Podrían los amigos de 'Base' tener acceso a él también? Creo que funcionaría mejor que la herencia si funciona así. – chris

+0

@chris: Un amigo de un amigo no es un amigo en C++. – jxh

+0

Entonces eso probablemente sería mejor que presentar la herencia. – chris

2

No hay manera fácil, no de hackear para lograr eso. C++ simplemente no tiene esa granularidad de control de acceso. Puede jugar con algo de herencia, pero una mayor complejidad supera cualquier ventaja que pueda tener esta restricción de acceso. Además, este enfoque no se escala, puede otorgar mayores permisos solo a una clase de amigo.

0

Tal vez un poco engorroso, pero se puede hacer que las clases anidadas donde la clase de anidación es amigo, entonces se puede agregar amigos por clase anidada. Esto le da un cierto nivel de granularidad:

#include <iostream> 

class Nesting 
{ 
    friend class Foo; 
    class Nested1 
    { 
    friend class Nesting; 
    public: 
    Nested1() : i(3) { } 
    private: 
    int i; 
    } n1; 
    class Nested2 
    { 
    friend class Nesting; 
    friend class Foo; 
    public: 
    Nested2() : j(5) { } 
    private: 
    int j; 
    } n2; 
    int f() { return n1.i; } 
}; 

class Foo 
{ 
public: 
    Foo(Nesting& n1) : n(n1) { } 
    int getJ() { return n.n2.j + n.f(); } 
private: 
    Nesting& n; 
}; 

int main() 
{ 
    Nesting n; 
    Foo foo(n); 
    std::cout << foo.getJ() << "\n"; 
} 
Cuestiones relacionadas