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

发布于 2024-10-08 15:56:25 字数 818 浏览 9 评论 0原文

假设我有一个类 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;
}

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

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 of F is necessary.
  • likewise, a class A::BF can be friend to A::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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

浪漫人生路 2024-10-15 15:56:25

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

7.3.1.2 命名空间成员定义

第 3 段

首先声明的每个名称
命名空间是的成员
命名空间
。如果朋友声明
非局部类首先声明一个
类或函数
(这意味着类或函数的名称是不合格的)友元类
或函数是成员
最里面的封闭命名空间。

// 假设 f 和 g 尚未定义。
无效 h(int);
模板无效 f2(T);
命名空间 A {
   X类{
   朋友无效 f(X); // A::f(X) 是朋友
      Y类{
         朋友无效g(); // A::g 是朋友
         朋友无效 h(int); // A::h 是朋友
         // ::h 不考虑
         朋友 void f2<>(int); // ::f2<>(int) 是朋友
      };
   };
   // A::f、A::g 和 A::h 在这里不可见
   XX;
   无效 g() { f(x); } // A::g 的定义
   void f(X) { /* ... */} // A::f 的定义
   void h(int) { /* ... */ } // A::h 的定义
   // A::f、A::g 和 A::h 在这里可见并且已知是友元
}

您的 friend class BF; 是命名空间 A 中的 A::BF 声明,而不是全局命名空间。您需要全局事先声明来避免此新声明。

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.

來不及說愛妳 2024-10-15 15:56:25

让我们考虑一下示例中的这 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 行完全遵循标准要求。

所有的困惑都是因为“朋友声明”很弱,您需要提供可靠的前向声明才能进一步使用。

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.

葮薆情 2024-10-15 15:56:25

因为如果您位于 namespace {} 块内,那么在全局命名空间中声明某些内容是没有意义的。 friend class BF; 起作用的原因是它的作用类似于隐式前向声明。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文