朋友宣言是真实的宣言吗?

acg*_*ant 5 c++

C++ Primer说:"重要的是要理解朋友声明会影响访问,但不是普通意义上的声明."

所以朋友声明应该只向朋友类/功能提供访问权限,它不是真正的声明.

但是,我尝试了这个程序,它2在GCC 5.2.0中成功编译并输出,出了什么问题?

#include <iostream>

class Tmp {
 public:
  Tmp(int a) : a_(a) {};

 private:
  int a_;

  friend void p(Tmp a) { std::cout << a.a_ << std::endl; }
};

// void p(Tmp a); I commented it, so there is not any declaration statement for p(Tmp a).

int main(void) {
  Tmp a(2);
  p(a);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

Bri*_*ian 10

朋友声明是技术意义上的真实声明:它是根据C++语言的语法声明.关键字friend是修改声明的说明符.

如果你真的想知道这本书的含义,你应该只看一下前面的文字.

在用于朋友声明之前,不需要声明类和非成员函数.当名称首次出现在朋友声明中时,隐含地假定该名称是周围范围的一部分.但是,朋友本身并未在该范围内声明(第7.2.1节,第270页).

即使我们在类中定义函数,我们仍然必须在类本身之外提供一个声明来使该函数可见.即使我们只从友谊授予类的成员中调用朋友,也必须存在声明.

友元声明与典型声明不同,因为大多数声明都会将它们声明的名称引入它们所在的作用域,然后可以立即使用这些名称:

int x;  // introduces the name x into this scope
x = 0;  // lookup of "x" finds the name just declared
Run Code Online (Sandbox Code Playgroud)

友元声明将声明的名称引入最近的封闭命名空间,而不是找到友元声明的类.所以在这个意义上它是不寻常的.但是,更不寻常的是,在最近的封闭范围内声明相同名称之前,友元声明引入的名称对于限定或非限定名称查找是不可见的.

换句话说,您可能无法在朋友声明后立即开始使用该名称.这可能是本书所说的朋友声明不是普通意义上的声明.

这是一个简单的例子:

#include <cstdio>
class C {
    friend void hello() { std::puts("Hello, world!"); }
};
int main() {
    hello();
}
Run Code Online (Sandbox Code Playgroud)

此程序格式错误,因为hello在调用之前未在全局命名空间中声明.http://coliru.stacked-crooked.com/a/3ae525122312c96c

您的示例恰好起作用,因为有一个特殊规则,即依赖于参数的查找发现在关联类中声明的朋友,即使它们尚未在命名空间范围内声明.在调用中p(a),由于a具有类类型Tmp,因此该类Tmp是关联类.


use*_*267 5

朋友声明和其他声明一样多,因为它们引入了名称。也许C ++ Primer应该选择更好的语言。

但是,对于合格或不合格的查找,看不到朋友声明(在没有其他同名声明的情况下)。您的示例由于ADL而工作,但是如您从下面的代码中可以看到,仅一个朋友声明不会使该名称可用于任何其他类型的查找:

struct Tmp {
  friend void p(Tmp);
  friend void q();
};

int main() {
  Tmp a;
  p(a);  // Argument-dependant lookup ==> ok!
  q();   // Unqualified lookup        ==> nope
  ::q(); // Qualified lookup          ==> also nope
}
Run Code Online (Sandbox Code Playgroud)
test.cpp: In function 'int main()':
test.cpp:9:9: error: 'q' was not declared in this scope
       q();
         ^
test.cpp:10:7: error: '::q' has not been declared
       ::q();
Run Code Online (Sandbox Code Playgroud)

  • “各种意义上的常规声明”“不会使名称可用于常规查找”?这是声明的第一个区别特征。 (2认同)
  • 不是普通的猫。至少,我从未见过。 (2认同)