简体   繁体   English

朋友声明是真正的声明吗?

[英]Is the friend declaration a real declaration?

C++ Primer says: C++ 入门 说:

It is important to understand that a friend declaration affects access but is not a declaration in an ordinary sense.重要的是要理解友元声明会影响访问,但不是一般意义上的声明。

So friend declaration should offer access authority only to the friend class/function, it is not a real declaration.所以友元声明应该只为友元类/函数提供访问权限,它不是真正的声明。

However, I tried this program, it complied successfully and outputs 2 in GCC 5.2.0, what's wrong?但是,我尝试了这个程序,它成功编译并在 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;
}

A friend declaration is a real declaration in the technical sense: it is a declaration according to the grammar of the C++ language.朋友声明是技术意义上的真正声明:它是根据 C++ 语言语法的声明。 The keyword friend is a specifier that modifies a declaration.关键字friend是修改声明的说明符。

If you really want to know what the book means, you should just look at the immediately preceding text.如果你真的想知道这本书的意思,你应该看看前面的文字。

Classes and nonmember functions need not have been declared before they are used in a friend declaration.类和非成员函数在用于友元声明之前无需声明。 When a name first appears in a friend declaration, that name is implicitly assumed to be part of the surrounding scope.当名称首次出现在友元声明中时,该名称被隐式假定为周围范围的一部分。 However, the friend itself is not actually declared in that scope (§7.2.1, p. 270).但是,朋友本身实际上并未在该范围内声明(第 7.2.1 节,第 270 页)。

Even if we define the function inside the class, we must still provide a declaration outside the class itself to make that function visible.即使我们在类内部定义了函数,我们仍然必须在类本身之外提供一个声明,以使该函数可见。 A declaration must exist even if we only call the friend from members of the friendship granting class.即使我们只从友谊授予类的成员中调用朋友,声明也必须存在。

The friend declaration is different from a typical declaration because most declarations introduce the names they declare into the scope in which they are found, and then those names may be immediately used:友元声明与典型声明不同,因为大多数声明将它们声明的名称引入到它们所在的作用域中,然后这些名称可能会立即被使用:

int x;  // introduces the name x into this scope
x = 0;  // lookup of "x" finds the name just declared

A friend declaration introduces the name declared into the nearest enclosing namespace, not the class in which the friend declaration is found.友元声明将声明的名称引入最近的封闭命名空间,而不是在其中找到友元声明的类。 So it is unusual in that sense.所以从这个意义上说这是不寻常的。 However, even more unusually, the name introduced by a friend declaration is not visible to either qualified or unqualified name lookup until the same name is declared at the nearest enclosing scope.然而,更不寻常的是,在最近的封闭范围内声明相同的名称之前,由朋友声明引入的名称对于限定或非限定名称查找都是不可见的

In other words, you may not be able to start using the name immediately after the friend declaration.换句话说,您可能无法在朋友声明之后立即开始使用该名称。 This is probably what the book means when it says the friend declaration is not a declaration in the ordinary sense.这大概就是这本书所说的朋友声明不是普通意义上的声明的意思。

Here is a simple example:这是一个简单的例子:

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

This program is ill-formed because hello was not declared in the global namespace before being called.该程序格式错误,因为hello在被调用之前没有在全局命名空间中声明。 http://coliru.stacked-crooked.com/a/3ae525122312c96c http://coliru.stacked-crooked.com/a/3ae525122312c96c

Your example only happens to work because there is a special rule that argument-dependent lookup finds friends declared inside associated classes even if they haven't been declared at namespace scope yet.您的示例只是碰巧起作用,因为有一个特殊规则,即参数相关查找会查找在关联类中声明的朋友,即使它们尚未在命名空间范围内声明。 In the call p(a) , since a has the class type Tmp , the class Tmp is an associated class.在调用p(a) ,由于a具有类类型Tmp ,因此类Tmp是关联类。

Friend declarations are as much a declaration as any other, as in they introduce a name;友元声明和其他声明一样都是声明,因为它们引入了一个名字; perhaps C++ Primer should have chosen its words better.也许 C++ Primer 应该更好地选择它的词。

A friend declaration however is not visible for qualified or unqualified lookup (in the absence of other declarations of the same name).但是,对于限定或非限定查找(在没有其他同名声明的情况下)时,朋友声明是不可见的。 Your example works due to ADL , but as you can see from the following a friend declaration alone will not make the name available for any other kind of lookup:您的示例由于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
}

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();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM