友元分为:友元函数和友元类
友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。
友元函数
问题:现在我们尝试去重载operator<<,然后发现我们没办法将operator<<重载成成员函数。因为cout的输出流对象和隐含的this指针在抢占第一个参数的位置。this指针默认是第一个参数也就是左操作数了。但是实际使用中cout需要是第一个形参对象,才能正常使用。所以我们要将operator<<重载成全局函数。但是这样的话,又会导致类外没办法访问成员,那么这里就需要友元来解决。operator>>同理。
解释:
| 12
 3
 4
 
 | class MyClass {public:
 MyClass operator+(const MyClass& other);
 };
 
 | 
在这种情况下,调用a + b实际上被编译器视为a.operator+(b)。
如果我们将operator<<重载为类的成员函数,那么左操作数必须是该类的对象,而不是流对象。这显然不符合实际使用的情况,因为我们通常需要的是将对象插入到输出流中。
代码示例:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 
 | class Date{
 public:
 Date(int year, int month, int day)
 : _year(year)
 , _month(month)
 , _day(day)
 {}
 ostream& operator<<(const Date& d)
 {
 cout << d._year << "-" << d._month << "-" << d._day;
 return cout;
 }
 private:
 int _year;
 int _month;
 int _day;
 };
 
 int main() {
 Date d(2017, 12, 24);
 cout << d << endl;
 return 0;
 }
 
 | 
友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。
代码示例:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 
 | class Date{
 public:
 friend ostream& operator<<(ostream& cout, const Date& d);
 friend istream& operator>>(istream& cin, Date& d);
 Date(int year, int month, int day)
 : _year(year)
 , _month(month)
 , _day(day)
 {}
 private:
 int _year;
 int _month;
 int _day;
 };
 
 ostream& operator<<(ostream& cout, const Date& d)
 {
 cout << d._year << "-" << d._month << "-" << d._day;
 return cout;
 }
 
 istream& operator>>(istream& cin, Date& d)
 {
 cin >> d._year;
 cin >> d._month;
 cin >> d._day;
 return cin;
 }
 
 int main() {
 Date d(2017, 12, 24);
 cout << d << endl;
 cin >> d;
 cout << d << endl;
 return 0;
 }
 
 | 
代码生成图
| 12
 3
 
 | 2017-12-242024 06 06
 2024-6-6
 
 | 
Note:friend ostream &operator<<( const D &d);这个代码会报错
原因
此外,operator<< 的函数参数应该包含两个参数:
- 一个 ostream类型的对象(通常为引用类型),表示输出流。
- 一个 const D&类型的对象,表示要输出的对象。
我认为是规定!
友元函数特性
- 友元函数可访问类的私有成员,但不是类的成员函数
- 友元函数不能用const修饰
- 友元函数可以在类定义的任何地方声明,不受类访问限定符限制
- 一个函数可以是多个类的友元函数
- 友元函数的调用与普通函数的调用和原理相同
友元类
友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。
- 友元关系是单向的,不具有交换性。
 比如下面的Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。
- 友元关系不能传递
 如果B是A的友元,C是B的友元,则不能说明C是A的友元。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 
 | class Date; class Time
 {
 friend class Date;
 public:
 Time(int hour = 14, int minute= 20, int second = 10)
 : _hour(hour)
 , _minute(minute)
 , _second(second)
 {}
 private:
 int _hour;
 int _minute;
 int _second;
 };
 
 class Date
 {
 public:
 Date (int year = 2000, int month = 01, int day = 16)
 : _year(year)
 , _month(month)
 , _day(day)
 {
 }
 
 void SetTimeOfDate(int hour, int minute, int second)
 {
 
 _t._hour = hour;
 _t._minute = minute;
 _t._second = second;
 }
 
 void print() {
 cout << _year << '-' << _month << '-' << _day << ' ';
 cout << _t._hour << ':' << _t._minute << ':' << _t._second << endl;
 }
 private:
 int _year;
 int _month;
 int _day;
 Time _t;
 };
 
 int main() {
 Date d;
 d.print();
 
 return 0;
 }
 
 | 
要点总结
- 友元就是让一个外部函数或者外部类能访问我的私有成员。
- 友元打破了原有的权限制度,所以十分危险,不建议使用
转载自:C++:友元函数与友元类的介绍