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是关联类.
朋友声明和其他声明一样多,因为它们引入了名称。也许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)
| 归档时间: |
|
| 查看次数: |
950 次 |
| 最近记录: |