5

Quiero un tipo Un que dará su dato escondido a un objeto de tipo T pero ocultar el dato de todos los demás. Mi compilador C++ pasa a ser GCC 4.4, pero eso no debería importar. ¿Por qué no funciona esto?Cómo ocultar un dato de todos, pero la clase T

#include <iostream> 

template <class T> class A { 
    private: 
    int n1; 
    public: 
    friend class T; 
    A(const int n0 = 0) : n1(n0) {} 
}; 

class B { 
    public: 
    int f(const A<B> a) const { return a.n1; } 
    B() {} 
}; 

int main() { 
    const A<B> a(5); 
    const B b; 
    const int m = b.f(a); 
    std::cout << m << "\n"; 
    return 0; 
} 

Por cierto, esto funciona bien, excepto que no logra ocultar el dato:

#include <iostream> 

template <class T> class A { 
    private: 
    int n1; 
    public: 
    int n() const { return n1; } 
    A(const int n0 = 0) : n1(n0) {} 
}; 

class B { 
    public: 
    int f(const A<B> a) const { return a.n(); } 
    B() {} 
}; 

int main() { 
    const A<B> a(5); 
    const B b; 
    const int m = b.f(a); 
    std::cout << m << "\n"; 
    return 0; 
} 

que C++ hace realmente no permite una clase de amigo que se especificará en tiempo de compilación como un parámetro de plantilla? Por qué no? Si no, ¿qué técnica alternativa debería usar para ocultar el dato? (Uno preferiría una técnica de tiempo de compilación si fuera posible.)

¿Cuál es mi malentendido aquí, por favor?

(I ver algunas respuestas a las preguntas relacionadas here y here, pero o bien no responden a mi pregunta en particular o que no entienden que lo hagan. En cualquier caso, tal vez yo estoy usando la técnica equivocada por completo. Aunque seguir interesado en por qué la clase de amigo T falla, lo que realmente quiero saber es cómo ocultar el dato, ya sea con un amigo o por otros medios.)

Gracias.

Respuesta

1

No conozco el estándar detrás de su error (consulte la respuesta de Xeo), pero encontré una solución para C++ 03. En lugar de hacer T un amigo, hacer que una de las funciones miembro T 's un amigo:

#include <iostream> 

template <class T> class A { 
    private: 
    int n1; 
    public: 
    friend int T::getN1(const A& a) const; 
    A(const int n0 = 0) : n1(n0) {} 
}; 

class B { 
    public: 
    int f(const A<B> a) const { return getN1(a); } 
    B() {} 
    private: 
    int getN1(const A<B>& a) const {return a.n1;} 
}; 

class C { 
    public: 
    int f(const A<B> a) const { return getN1(a); } 
    C() {} 
    private: 
    // Error, n1 is a private member of A<B> 
    int getN1(const A<B>& a) const {return a.n1;} 
}; 

int main() { 
    const A<B> a(5); 
    const B b; 
    const int m = b.f(a); 
    std::cout << m << "\n"; 
    return 0; 
} 

Alternativamente, se puede hacer una clase anidada/estructura de T ser un amigo de A. Esto puede ser más conveniente si hay varios miembros privados de A a los que desea que T tenga acceso.

#include <iostream> 

template <class T> class A { 
    private: 
    int n1; 
    public: 
    friend class T::AccessToA; 
    A(const int n0 = 0) : n1(n0) {} 
}; 

class B { 
    public: 
    int f(const A<B> a) const { return AccessToA::getN1(a); } 
    B() {}; 
    private: 
    friend class A<B>; 
    struct AccessToA 
    { 
     static int getN1(const A<B>& a) {return a.n1;} 
    }; 
}; 

class C { 
    public: 
    int f(const A<B> a) const { return AccessToA::getN1(a); } 
    C() {}; 

    private: 
    friend class A<C>; 
    struct AccessToA 
    { 
     // Error, n1 is a private member of A<B> 
     static int getN1(const A<B>& a) {return a.n1;} 
    }; 
}; 

int main() { 
    const A<B> a(5); 
    const B b; 
    const int m = b.f(a); 
    std::cout << m << "\n"; 
    return 0; 
} 
+0

Buen consejo. A menos que se me ocurra algo mejor, debería seguir el consejo. Gracias. – thb

+0

También revisa la frase clave usada por Xeo, así como el idioma de abogado-cliente. Ha pasado un tiempo desde que leí sobre ellos, por lo que mi solución puede ser una variante de esos modismos. –

4

Tu compilador es simplemente demasiado viejo. C++ 11 le permite declarar parámetros de plantilla como amigos.

§11.3 [class.friend] p3

Una declaración amigo que no declarar una función deberá tener una de las siguientes formas:

  • friendelaborated-type-specifier;
  • friendsimple-type-specifier;
  • friendtypename-specifier;

Si el especificador de tipo en una declaración friend designa un tipo de clase (posiblemente cv-cualificada), que clase se declara como un friend; de lo contrario, la declaración de amigo se ignora.

Y aún contiene un ejemplo de un parámetro de plantilla como un amigo:

class C; 
// [...] 
template <typename T> class R { 
    friend T; 
}; 

R<C> rc; // class C is a friend of R<C> 
R<int> ri; // OK: "friend int;" is ignored 

C++ 03 por desgracia no tiene ninguna manera de hacer esto, sin embargo se puede simplemente amigo una sola función y dejar libre que actúan como código "pegamento" que toma los datos de una clase y los pasa a la otra. Otra forma podría ser passkey pattern.

+0

Ya veo. Gracias. Gracias también por el esclarecedor enlace de la llave maestra. – thb

Cuestiones relacionadas