C++中的友元

序言

您知道,C++控制对类对象私有部分的访问。通常,公有类方法提供唯一的访问途径,但是有时候这种限制太严格,以致于不适合特定的编程问题。在这种情况下,C++提供了另外一种形式的访问权限:友元。友元有3种:

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

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

为什么要使用友元函数

在前面的Time类示例中,重载的乘法运算符与其他两种重载运算符的差别在于,它使用了两种不同的类型。也就是说,加法和减法运算符都结合两个 Time 值,而乘法运算符将一个 Time 值与一个 double值结合在一起。这限制了该运算符的使用方式。记住,左侧的操作数是调用对象。也就是说,下面的语句:

A = B * 2.75;

将被转换为下面的成员函数调用

A = B.operator*(2.75);

但下面的语句又如何呢?

A = 2.75 * B;

从概念上说,2.75 * B应与B *2.75相同,但第一个表达式不对应于成员函数,因为2.75不是Time类型的对象。记住,左侧的操作数应是调用对象,但2.75不是对象。因此,编译器不能使用成员函数调用来替换该表达式。
有一种解决方式是使用非成员函数,非成员函数不是由对象调用的,它使用的所有值(包括对象)都是显式参数。这样,编译器能够将下面的表达式:

A = 2.75 * B;

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

A = operator*(2.75, B);

该函数的原型如下:

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

使用非成员函数可以按所需的顺序获得操作数(先是 double,然后是 Time),但引发了一个新问题:非成员函数不能直接访问类的私有数据,至少常规非成员函数不能访问。然而,有一类特殊的非成员函数可以访问类的私有成员,它们被称为友元函数。

创建友元

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

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

该原型意味着下面两点:
虽然operator*( )函数是在类声明中声明的,但它不是成员函数,因此不能使用成员运算符来调用;
虽然operator*( )函数不是成员函数,但它与成员函数的访问权限相同。
第二步是编写函数定义。因为它不是成员函数,所以不要使用 Time::限定符。另外,不要在定义中使用关键字friend,定义应该如下:

Time operator*(double m, const Time & t)
{
	Time result;
	long totalminutes = t.hours * mult * 60 + t.minutes * mult;
	result.hours = totalminutes / 60;
	result.minutes = totalminutes % 
}

有了上述声明和定义后,下面的语句:

A = 2.75 * B;

将转换为如下语句,从而调用刚才定义的非成员友元函数:
总之,类的友元函数是非成员函数,其访问权限与成员函数相同。

友元没有违背OOP

乍一看,您可能会认为友元违反了OOP数据隐藏的原则,因为友元机制允许非成员函数访问私有数据。然而,这个观点太片面了。相反,应将友元函数看作类的扩展接口的组成部分。只有类声明可以决定哪一个函数是友元,因此类声明仍然控制了哪些函数可以访问私有数据。总之,类方法和友元只是表达类接口的两种不同机制。


总结

暂时没有

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值