问题
Suppose I have a class F
that should be friend to the classes G
(in the global namespace) and C
(in namespace A
).
- to be friend to
A::C
,F
must be forward declared. - to be friend to
G
, no forward declaration ofF
is necessary. - likewise, a class
A::BF
can be friend toA::C
without forward declaration
The following code illustrates this and compiles with GCC 4.5, VC++ 10 and at least with one other compiler.
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;
}
To me this seems inconsistent. Is there a reason for this or is it just a design decision of the standard?
回答1:
C++
Standard ISO/IEC 14882:2003(E)
7.3.1.2 Namespace member definitions
Paragraph 3
Every name first declared in a namespace is a member of that namespace. If a friend declaration in a non-local class first declares a class or function (this implies that the name of the class or function is unqualified) the friend class or function is a member of the innermost enclosing namespace.
// 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 }
Your friend class BF;
is a declaration of A::BF
in namespace A rather than global namespace. You need the global prior declaration to avoid this new declaration.
回答2:
Let's take into account these 3 code lines from your sample:
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.
C++ standard in paragraph 7.3.1.2, point 3 ( Namespace member definitions) says:
The friend declaration does not by itself make the name visible to unqualified lookup (3.4.1) or qualified lookup (3.4.3). [ Note: The name of the friend will be visible in its namespace if a matching declaration is provided at namespace scope (either before or after the class definition granting friendship). —end note ]
And line 2 follows exactly what standard requires.
All confusion is because "friend declaration" is weak, you need to provide solid forward declaration for further usage.
回答3:
Because it wouldn't make sense to be able to declare something in the global namespace if you're inside a namespace {}
block. The reason friend class BF;
works is that it acts like an implicit forward declaration.
来源:https://stackoverflow.com/questions/4492062/why-does-a-c-friend-class-need-a-forward-declaration-only-in-other-namespaces