友元函数的单独声明

Separate declaration for friend function

本文关键字:声明 单独 函数 友元      更新时间:2023-10-16

我正在读C++初级读本。上面写着:

朋友声明仅指定访问权限。这不是对作用如果我们希望类的用户能够调用friend函数,那么我们还必须将函数与友元声明分开声明。为了使类的用户可以看到一个朋友,我们通常声明每个朋友(在类之外)在与类本身相同的头中

小心代码中的箭头。它在上面提到的文本中提出了我的问题。

header.h

#ifndef HEADER_H
#define HEADER_H
#include <iostream>
#include <string>
using namespace std;
class Husband{
    friend void change_salary(int changed_salary, Husband &ob);
public:
    Husband() {}
    Husband(unsigned new_salary) : salary{ new_salary } {}
private:
    int salary;
};
//void change_salary(int changed_salary, Husband &ob);  <----Code Compiles without even this declaration
#endif

main.cpp

#include "header.h"
void change_salary(int changed_salary, Husband &ob)
{
    cout << "salary increased by 1000";
    ob.salary = changed_salary;
}

int main()
{
    Husband hs1{ 3000 };
    change_salary(4000, hs1);  // <---- Able to use function without explicit declaration outside of class in header
    return 0; 
}

如果在声明后在声明的同一文件中使用函数,则头文件中不需要原型,这就是您在main.cpp中所做的。

在头文件中放入原型有助于其他文件中的代码,或者在同一文件中但更高的文件中找到函数。在头文件中创建原型通常是一种很好的做法,以使API对人类读者清晰可见。但在这里的情况下,它并不是严格要求编译的。

友元函数声明是类设计的一部分。如果没有在类标头(或某些包含的标头)中声明函数,则您的设计是不完整的(强制用户实现该函数,或为某些用户实现打开大门,或导致违反一个定义规则(ODR))。

在定义使用它的main()之前,您已经提供了change_salary的定义,因此该函数始终可见,没有任何问题。但假设您将定义移动到main()的定义之下(或移动到一个单独的.cpp文件)。

int main()
{
    Husband hs1{ 3000 };
    change_salary(4000, hs1);
}
void change_salary(int changed_salary, Husband &ob)
{
    cout << "salary increased by 1000";
    ob.salary = changed_salary;
}

即使在这种情况下,代码也将继续编译,因为change_salary将通过依赖于参数的名称查找找到(因为第二个参数的类型为Husband&)。

现在,让我们尝试通过在main()中形成指向change_salary的指针来显式引用它。

void (*p)(int, Husband&) = &change_salary;

这将无法编译,因为ADL在这种情况下不适用,并且change_salary的定义对main()不可见。

但是,如果取消注释头中change_salary的声明,则代码将进行编译。这大概就是书中所说的让类用户看到朋友的意思。