友元
C++控制对类对象数据的私有访问,通常情况下,公有方法提供唯一的访问途径,有时由于这种限制太严格,以致于不适合特定的编程问题。在这种情况下,C++提供了一种形式访问权限:友元
友元有三种:
- 友元函数
- 友元类
- 友元成员函数
通过让函数成为类的友元,可以赋予该函数与类的成员函数相同的访问权限。以下主要介绍友元函数
创建友元函数
创建友元函数的第一步是将其原型放在类声明中,并在原型中附上friend关键字
eg: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*m*60+t.minutes*m;
result.hours=totalminutes/60;
result.minutes=totalminutes&60;
return result;
}
定义Time A,B
A=2.75*B;
将转换为
A=operator*(2.75,B);
*总之,类的友元函数是非成员函数,其访问权限与成员函数相同
常用的友元函数:重载<<运算符
<<运算符最初在C中的运算意义是位运算符,在c++中可以作为cout的输出工具。以此看来,<<运算符实际已经被重载过了,如果设trip是一个Time类(自定义的类)的对象,并要执行以下语句:
cout<<trip;
通常情况下编译器会报错,因为cout无法识别trip的类型,可以通过重载<<运算符来解决这个问题。
由于ostream类声明中包含的相应的重载operator<<()的定义,但修改iostream文件是个很危险的想法。因此得在Time类中定义这个重载函数。
这个重载函数必须是友元函数,原因:
如果是非友元,并使用Time来重载<<,那么Time将是第一个操作数,最终意味着必须这样使用<<
trip<<cout;
所以使用友元函数来定义:
void operator(ostream &os,const Time &t){
os<<t.hours<<"hours, "<<t.minutes<<"minutes";
}
存在的问题,上述定义无法识别以下语句
Time t1,t2,t3;
cout<<t1<<t2<<t3<<endl;
这是因为ostream定义中<<运算符要求左边的参数必须是一个ostream类型的但上述第一个cout<<t1返回的是一个void类型的数据,所以重新修改友元函数定义
ostream& operator(ostream &os,const Time &t){
os<<t.hours<<"hours, "<<t.minutes<<"minutes";
return os;
}