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

时间:2015-08-24 05:58:48

标签: c++

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;
}

1 个答案:

答案 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();
}

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

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