友元

概述:C++ 友元

[toc]

友元

C++ 提供了另外一种形式的访问权限:友元。友元有3种:

  • 友元函数
  • 友元类
  • 友元成员函数

通过让函数成为类的友元,可以赋予该函数与类的成员函数相同的访问权限。

为何需要友元

在为类重载二元运算符时(带两个参数的运算符)常常需要友元。将 Time 对象乘以实数就属于这种情况。

下面的语句:

1
A = B * 2.75

将被转换成:

1
A = B.operator*(2.75);

但下面的语句又如何呢?

1
A = 2.75 * B;

从概念上说,2.75*BB*2.75 相同,但第一个表达式不对应于成员函数,因为2.75不是 Timer 类型的对象。记住,左侧的操作数应是调用对象,但2.75不是对象。因此,编译器不能使用成员函数调用来替换该表达式。

解决这个难题的一种方式是,告知每个人(包括程序员自己),只能按 B*2.75 的格式编写,不能写成2.75*B。这是一种对服务器友好-客户警惕的(server-friendly, client-beware)解决方案,与OOP无关。

当然,上述的问题也有解决方案——非成员函数。非成员函数不是由对象调用的,它使用的所有值(包括对象)都是显式参数。这样,编译器能够将下面的表达式:

1
A = 2.75 * B;

与下面的非成员函数调用匹配:

1
A = operator*(2.75,B);

该函数的原型如下:

1
Time operator*(double m, const Time &t);

对于非成员重载运算符函数来说,运算符表达式左边的操作数对应于运算符函数的第一个参数,运算符表达式右边的操作数对应于运算符函数的第二个参数。而原来的成员函数可以访问类的私有成员,它们被称为友元函数。

创建友元

创建友元函数的第一步是将其原型放在类声明中,并在原型声明前加上关键字 friend:

1
friend Time operator*(double m, const Time & t);

该原型意味着下面两点:

  • 虽然 operator*() 函数是在类声明中声明的,但它不是成员函数,因此不能使用成员运算符来调用;
  • 虽然 operator*() 函数不是成员函数,但它与成员函数的访问权限相同。

第二步是编写函数定义。因为它不是成员函数,所以不要使用 Time:: 限定符。另外,不要在定义中使用关键字 friend,定义如下:

1
2
3
4
5
6
7
8
Time operator*(double m,const Tlme & t)// frlend not ued in definition
{
Time result;
long totalminutes = t.hours * m * 60 + t.minutes * m;
result.hours = totalminutes/60;
result.minutes = totalminutes % 60;
return result;
}

总之,类的友元函数是非成员函数,其访问权限与成员函数相同。


友元
https://hodlyounger.github.io/D_立志博览群书/《C++ primer plus》/第11章 使用类/【CPP】友元/
作者
mingming
发布于
2023年10月27日
许可协议