为什么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;
工作就是它像一个隐式的前向声明。