为什么C ++的朋友类只需要在其他命名空间中进行前向声明?

假设我有一个F类,它应该是类G (在全局命名空间)和C (在命名空间A )中的朋友。

  • 要成为A::C朋友, F必须被转发声明。
  • G朋友,没有F前向声明是必要的。
  • 同样,类A::BF可以成为A::C朋友,无需前向声明

下面的代码演示了这一点,并用GCC 4.5,VC ++ 10和至less另外一个编译器编译。

 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() { cc = 2; } private: C c; }; } // namespace A class F { public: F() { gg = 3; cc = 2; } private: G g; A::C c; }; int main() { F f; } 

对我来说这似乎不一致。 这是有原因还是只是标准的devise决定?

C++标准ISO/IEC 14882:2003(E)

7.3.1.2名字空间成员定义

第3段

名称空间中首先声明的每个名称都是该名称空间的成员 。 如果非本地类中的朋友声明首先声明了一个类或函数(这意味着该类或函数的名称是不合格的),则该朋友类或函数是最内层的封闭名称空间的成员。

 // 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 } 

你的friend class BF; 是名称空间A中的A::BF的声明,而不是全局名称空间。 你需要全球性的事先声明来避免这个新的声明。

我们来考虑一下你的例子中的3个代码行:

 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. 

第7.3.1.2节第3点(命名空间成员定义)中的C ++标准说:

这个朋友声明本身并不使得这个名字对于不合格的查找(3.4.1)或合格的查找(3.4.3)是可见的。 [注意:如果在命名空间范围(在授予友谊的类定义之前或之后)提供了匹配声明,则该朋友的名字将在其名称空间中可见。 – 注意]

第2行完全遵循标准要求。

所有的困惑都是因为“朋友宣言” 薄弱 ,需要提供坚实的前瞻性声明供进一步的使用。

因为如果你在一个namespace {}块里,能够在全局命名空间中声明一些东西是没有意义的。 friend class BF;的原因friend class BF; 工作就是它像一个隐式的前向声明。