C++中友元函数(friend)解析
文章转自公众号:Coder梁(ID:Coder_LT)
我们知道C++控制对象的私有部分的访问,只能通过公共的接口。这样的设计当然没错,但有的时候也会显得过于严格,产生一些问题。
因此C++提供了另外一种形式的访问权限,叫做友元(friend
)。
友元有三种,分别是友元函数、友元类和友元成员函数。
通过让函数成为类的友元,可以赋予该函数与类成员函数一样的访问权限,也就是说我们可以在友元函数当中访问类的私有成员变量。
在介绍友元函数的使用之前,我们需要先了解为什么需要友元函数。C++ Primer
中给了一个非常不错的例子,在之前运算符重载的例子当中,我们实现了一个类Time
。用来记录时间,假设我们需要重载它的*运算符,能够允许一个时间对象和一个浮点数相乘。
很明显,我们只需要重载运算符*即可:
Time Time::operator*(const double x) { // todo }
我们在使用的时候大概是这样:
Time a, b; a = b * 32.5;
但是这里有一个小问题,我们写成a = b * 32.5
;可以,但如果反过来写成32.5 * b
就不行了。因为对于b * 32.5
来说本质上是b调用了operator
*函数,等价于a = b.opeartor*(32.5)
;。但后者就不行了,要怎么解决呢,只能另外实现一个函数来解决了,这个函数有两个input,分别是double
和Time
类型,返回一个Time
类型。
Time operator*(double m, const Time &t);
但这又有了新的问题,由于这不是一个成员函数,不能直接访问类的私有数据。为了破例让它能够访问,我们需要将它设置成友元。
创建友元的方法很简单,我们只需要在函数签名之前加上关键字friend
。
friend Time operator*(double m, const Time &t);
它有两个含义:
- 它不是成员函数,因此不能使用成员函数运算符来调用
- 它与成员函数的访问权限相同,即可以访问所有
private
和public
数据
由于友元函数不是成员函数,所有我们在实现的时候不需要使用Time::
限定符,也不用在实现当中加上关键字friend
,
函数的实现如下:
Time operator*(double m, const Time &t) { Time result; long totalminutes = t.hours * m * 60 + t.minutes * m; result.hours = totalminutes / 60; result.minutes = totalminutes % 60; return result; }
我们在函数当中直接访问了hours
和minutes
成员变量,因此函数必须是友元函数。
当然我们可以把函数稍微变换一下,就可以不必是友元函数了:
Time operator*(double m, const Time &t) { return t * m; // 调用了t.operator*(m) }
在这个函数当中,我们没有显式地访问私有变量,因此可以不必是友元。