为啥 C++ 友元类只需要在其他命名空间中进行前向声明?
Posted
技术标签:
【中文标题】为啥 C++ 友元类只需要在其他命名空间中进行前向声明?【英文标题】:Why does a C++ friend class need a forward declaration only in other namespaces?为什么 C++ 友元类只需要在其他命名空间中进行前向声明? 【发布时间】:2011-05-28 09:12:04 【问题描述】:假设我有一个类 F
应该是类 G
(在全局命名空间中)和 C
(在命名空间 A
中)的朋友。
A::C
的朋友,F
必须前向声明。
要成为G
的朋友,无需前向声明F
。
同样,类 A::BF
可以成为 A::C
的朋友,无需前向声明
以下代码说明了这一点,并可以使用 GCC 4.5、VC++ 10 以及至少一个其他编译器进行编译。
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;
在我看来,这似乎不一致。这是有原因的还是只是标准的设计决定?
【问题讨论】:
【参考方案1】: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::BF
在命名空间A 而非全局命名空间中的声明。您需要全局先验声明来避免这个新声明。
【讨论】:
一个理性的人可能会问为什么写“friend class ::F;
”(如 OP 的代码所示)是不够的,从而显式地将F
推入全局命名空间。我认为答案是“一个合格的 id 永远不会声明一个新名称”,但我不确定标准在这一点上到底说了什么。
@Zack 这也是我最初的问题:当我在另一个命名空间中移动一个类时,为什么需要添加前向声明?但是已经有一些关于这个主题的讨论(例如***.com/questions/2059665、***.com/questions/1368642)。似乎不需要在同一范围内进行前向声明是标准作者授予的便利。【参考方案2】:
让我们考虑一下示例中的这 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 行完全符合标准的要求。
所有的困惑都是因为“朋友声明”是弱,您需要提供可靠的前向声明以供进一步使用。
【讨论】:
【参考方案3】:因为如果您在 namespace
块内,那么在全局命名空间中声明某些内容是没有意义的。 friend class BF;
起作用的原因是它的行为类似于隐式前向声明。
【讨论】:
以上是关于为啥 C++ 友元类只需要在其他命名空间中进行前向声明?的主要内容,如果未能解决你的问题,请参考以下文章