C ++ Primer说:“重要的是要理解朋友声明会影响访问,但不是普通意义上的声明。”。
因此,朋友声明应仅向朋友类/功能提供访问权限,这不是真正的声明。
但是,我尝试了这个程序,它成功编译并在GCC 5.2.0中输出2
,出了什么问题?
#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;
}
答案 0 :(得分:9)
友情声明是技术意义上的真实声明:它是根据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
友元声明将声明的名称引入最近的封闭命名空间,而不是找到友元声明的类。所以在这个意义上它是不寻常的。但是,更不寻常的是,在最近的封闭范围内声明相同的名称之前,友情声明引入的名称不可见以进行限定或非限定名称查找。
换句话说,您可能无法在朋友声明后立即开始使用该名称。这可能是本书所说的朋友声明不是普通意义上的声明的意思。
这是一个简单的例子:
#include <cstdio>
class C {
friend void hello() { std::puts("Hello, world!"); }
};
int main() {
hello();
}
此程序格式错误,因为在调用之前未在全局命名空间中声明hello
。 http://coliru.stacked-crooked.com/a/3ae525122312c96c
您的示例恰好起作用,因为有一个特殊规则,即依赖于参数的查找发现在关联类中声明的朋友,即使它们尚未在命名空间范围内声明。在致电p(a)
中,由于a
的班级类型为Tmp
,因此班级Tmp
是相关联的班级。