c++ - 为什么我不能转发声明内部友元类?

标签 c++ friend

此代码可以在 MSVC 2013 下编译,但不能在 Clang 500.2.79 下编译:

class A
{
    friend class B;
    B *b;
};

class B
{
};

> error: unknown type name 'B'

为什么?

最佳答案

友元声明本身并不(总是)需要前向声明,但友元指针/引用的后续使用却需要。VC++ 似乎允许语言规范不允许的功能。不过,函数的查找规则确实比类稍微宽松一些:

C++11 §7.3.1.2/3 (Namespace member definitions) [namespace.memdef]:

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, function, class template or function template the friend is a member of the innermost enclosing namespace. The name of the friend is not found by unqualified lookup (3.4.1) or by qualified lookup (3.4.3) until a matching declaration is provided in that namespace scope (either before or after the class definition granting friendship). If a friend function or function template is called, its name may be found by the name lookup that considers functions from namespaces and classes associated with the types of the function arguments (3.4.2).

规范示例:

// Assume f and g have not yet been declared.
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
}

using A::x;
void h() {
  A::f(x);
  A::X::f(x); // error: f is not a member of A::X
  A::X::Y::g(); // error: g is not a member of A::X::Y
}

内部(“嵌套”)类会自动成为好友,但必须在内部定义它们,而不仅仅是声明:

class A {
  public:
    // This class is nested, and referred to as "A::B" outside of A.
    class B {
      public:
        int foo(A &a) { return a.x; } // OK by default to access A's privates
    };

  private:
    int x;
};

A a;
A::B b;
int n = b.foo(a);

如果您移动 B 的定义(或者只是进行前向声明),您可以正确地添加非嵌套类:

class B;

class A {
  friend class B; // OK, since B (not nested) declared before this directive
  B *b; 
}

class B { }; // can define B later, since only B pointer/references used earlier

关于c++ - 为什么我不能转发声明内部友元类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23704266/

相关文章:

c++ - 如何定义在两个类之外的模板类内部的非模板类中声明的友元函数?

c++ - 可以在 C++03 中有条件地声明友元类吗?

c# - 从托管代码调用非托管 DLL 函数时出错

c++ - C++ 从内存中删除对象

C++ 友元 vs 公共(public)

c++ - 我对友元函数的理解

C++模板类友元运算符重载

c++ - OpenGL 没有按预期绘制

c++ - 混合抽象类和模板,灾难的秘诀?

c++ - Typedef 在第一个函数定义后不起作用?