c++ - resueltos - miembros de una clase en programacion orientada a objetos
¿Por qué una clase de amigo de C++ necesita una declaración directa solo en otros espacios de nombres? (3)
Norma C++
ISO/IEC 14882:2003(E)
7.3.1.2 Definiciones de miembro de espacio de nombres
Párrafo 3
Cada nombre declarado por primera vez en un espacio de nombres es un miembro de ese espacio de nombres . Si una declaración de amigo en una clase no local declara primero una clase o función (esto implica que el nombre de la clase o función no está calificado), la clase o función amiga es un miembro del espacio de nombres más interno que lo rodea.
// Assume f and g have not yet been defined. void h(int); template <class T> void f2(T); namespace A { class X { friend void f(X); // A::f(X) is a friend class Y { friend void g(); // A::g is a friend friend void h(int); // A::h is a friend // ::h not considered friend void f2<>(int); // ::f2<>(int) is a friend }; }; // A::f, A::g and A::h are not visible here X x; void g() { f(x); } // definition of A::g void f(X) { /* ... */} // definition of A::f void h(int) { /* ... */ } // definition of A::h // A::f, A::g and A::h are visible here and known to be friends }
Tu friend class BF;
es una declaración de A::BF
en el espacio de nombres A en lugar del espacio de nombres global. Necesita la declaración previa global para evitar esta nueva declaración.
Supongamos que tengo una clase F
que debería ser amiga de las clases G
(en el espacio de nombres global) y C
(en el espacio de nombres A
).
- ser amigo de
A::C
,F
debe ser declarado adelante. - para ser amigo de
G
, no es necesaria ninguna declaración directa deF
- asimismo, una clase
A::BF
puede ser amiga deA::C
sin declaración directa
El siguiente código ilustra esto y compila con GCC 4.5, VC ++ 10 y al menos con otro compilador.
class G {
friend class F;
int g;
};
// without this forward declaration, F can''t be friend to A::C
class F;
namespace A {
class C {
friend class ::F;
friend class BF;
int c;
};
class BF {
public:
BF() { c.c = 2; }
private:
C c;
};
} // namespace A
class F {
public:
F() { g.g = 3; c.c = 2; }
private:
G g;
A::C c;
};
int main()
{
F f;
}
Para mí esto parece inconsistente. ¿Hay alguna razón para esto o solo es una decisión de diseño del estándar?
Porque no tendría sentido poder declarar algo en el espacio de nombres global si estás dentro de un bloque de namespace {}
. La razón friend class BF;
funciona es que actúa como una declaración directa implícita.
Tomemos en cuenta estas 3 líneas de código de su muestra:
1. friend class F; // it creates "friend declaration", (that''s not the same as ordinary forward declaration
2. class F; // without this forward declaration, F can''t be friend to A::C <-- this is ordinary forward declaration
3. friend class ::F; // this is qualified lookup (because of ::), so it needs previous declaration, which you provide in line 2.
El estándar de C ++ en el párrafo 7.3.1.2, punto 3 (definiciones de miembro de espacio de nombres) dice:
La declaración de amigo no hace que el nombre sea visible para búsqueda no calificada (3.4.1) o búsqueda calificada (3.4.3). [Nota: El nombre del amigo será visible en su espacio de nombres si se proporciona una declaración coincidente en el ámbito del espacio de nombres (ya sea antes o después de la definición de clase que otorga la amistad). -finalizar nota]
Y la línea 2 sigue exactamente lo que requiere el estándar.
Toda la confusión se debe a que la "declaración de amigo" es débil , debe proporcionar una declaración directa sólida para un uso posterior.