11.3

11.3 友元

C++控制对类对象私有部分的访问, 公有类方法是唯一的访问途径。
C++提供了另外一种形式的访问权限:友元函数
友元函数的分类
友元函数
友元类
友元成员函数
通过让函数称为类的友元, 赋予函数与类相同的访问权限:友元函数
其他两种友元将在第15章介绍
在为类重载二元运算符时, 经常会用到友元
在Time的示例中
A = B * 2.75;
相当于
A = B.operator*(2.75);
但是
A = 2.75 * B;
解决:
1.规定只能使用B * 2.75的方式
2.非成员函数
A = 2.75 * B;
相当于
A = operator*(2.75, B);
函数的原型:
Time operator*(double m, const Time & t);
对于非成员重载运算符函数来说, 运算符表达式左边的操作数对应于第一个参数, 右边的对应第二个。
但是非成员函数不能直接访问类的私有数据。但是友元函数可以。

创建友元

声明

将声明放在类声明中, 加上关键字 friend
friend Time operator*(double m, const Time & t);
该原型表明:
operator *()函数是在类声明中声明的, 但它不是成员函数, 因此不能使用成员运算符来调用
operator *()函数不是成员函数, 但它和成员函数访问权限相同

定义

不要加关键字:friend, 不要加类限定
Time operator *(double m, const Time & t)
{
... ...
}
有了上述声明和定义后, 下面的语句:
A = 2.75 * B;
相当于
A = operator*(2.75, B); // 调用刚才定义的非成员友元函数
Time operator *(double m, const Time & t)
{
return t * m; // 可以翻转操作顺序
}

常用的友元:重载<<运算符

Time trip;
cout << trip;
<<是可以被重载的C++运算符之一

第一个版本

void operator<<(ostream & os, const Time & t)
{
os << t.hours << " hours, " << t.minutes << " minutes";
}
选择友元或者非友元
其他ostream对象
cerr:将输出发送到标准输出流--默认显示器。
可以将标准错误重定向到文件。

第二个版本

第一个版本不允许:
cout << trip << endl;
cout操作:
int x = 5;
int y = 8;
cout << x << y;
// C++从左向右读取输出语句, 相当于:
(cout << x) << endl;
ostream & operator<<(ostream & os, const Time & t)
{
os << t.hours << " hours, " << t.minutes << " minutes";
return os;
}
继承使得ostream对象能够指向ostream和ofstream对象
ofstream fout
fout << trip;
一般来说要重载 << 运算符显示一个c_name类对象, 可以使用友元函数
ostream & operator << (ostream & os, const c_name & obj)
{
os << ... ;
return os;
}