为什么 C++ 朋友类只需要在其他命名空间中进行前向声明?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4492062/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does a C++ friend class need a forward declaration only in other namespaces?
提问by pesche
Suppose I have a class F
that should be friend to the classes G
(in the global namespace) and C
(in namespace A
).
假设我有一个类F
应该是类G
(在全局命名空间中)和C
(在命名空间中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
- 要成为朋友
A::C
,F
必须向前声明。 - 成为朋友
G
,不需要预先声明F
。 - 同样,一个类
A::BF
可以成为朋友A::C
而不需要前向声明
The following code illustrates this and compiles with GCC 4.5, VC++ 10 and at least with one other compiler.
以下代码说明了这一点,并使用 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;
}
To me this seems inconsistent. Is there a reason for this or is it just a design decision of the standard?
对我来说,这似乎不一致。这是有原因的还是只是标准的设计决定?
采纳答案by Alexey Malistov
C++
Standard ISO/IEC 14882:2003(E)
C++
标准 ISO/IEC 14882:2003(E)
7.3.1.2 Namespace member definitions
7.3.1.2 命名空间成员定义
Paragraph 3
第 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 }
在命名空间中首先声明的每个名称都是该命名空间的成员。如果非局部类中的友元声明首先声明了一个类或函数(这意味着类或函数的名称是不合格的),则友元类或函数是最内部封闭命名空间的成员。
// 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.
您friend class BF;
是A::BF
在命名空间 A 而不是全局命名空间中的声明。您需要全局事先声明以避免此新声明。
回答by LookAheadAtYourTypes
Let's take into account these 3 code lines from your sample:
让我们考虑一下您的示例中的这 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.
C++ standard in paragraph 7.3.1.2, point 3 ( Namespace member definitions)says:
第 7.3.1.2 段中的 C++ 标准,第 3 点(命名空间成员定义)说:
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 ]
友元声明本身不会使名称对非限定查找 (3.4.1) 或限定查找 (3.4.3) 可见。[注意:如果在命名空间范围内(在授予友谊的类定义之前或之后)提供匹配声明,则朋友的名称将在其命名空间中可见。——尾注]
And line 2 follows exactly what standard requires.
第 2 行完全遵循标准的要求。
All confusion is because "friend declaration" is weak, you need to provide solid forward declaration for further usage.
所有的混乱都是因为“朋友声明”很弱,您需要提供可靠的前向声明以供进一步使用。
回答by Billy ONeal
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.
因为如果你在一个namespace {}
块内,那么在全局命名空间中声明一些东西是没有意义的。有效的原因friend class BF;
是它就像一个隐式的前向声明。