概念
- 在类的内部使用friend 关键字取修饰 类/函数的声明,使得这个函数/类 成为 该类的友元函数/友元类
- 友元函数/友元类的声明可以在任意的位置进行,不论是在 public 、private、protected区域下,效果都是一样的,都是获取类的成员变量的权限!
- 友元函数/友元类具有访问类内部成员变量的权限,但并不是类的成员
- 友元函数在声明时需要使用friend修饰,但是在定义时不需要
- 友元函数/友元类是单向的,例如A类中有一个友元类B,B类的成员函数可以使用A类的成员变量,但是A类的成员变量不能使用B类的成员函数
- 友元函数不具有传递性,例如A类的内部有友元类B,B类内部有友元类C,类B可以用类A的成员变量,类C可以用类B的成员变量,但是类C不能用类A的成员变量。
友元函数的实现方式
1、友元函数是普通的全局函数
cpp
#include <iostream>
using namespace std;
class A
{
private:
int A;
public:
print(){};
//声明全局函数 person 是 类A 的友元函数
friend void person (int &x);
}
void person(int &x)
{
//使用了类A的成员变量age
cout << "age=" << p.age << endl;
}
int main ()
{
A p(22);
person(p);
return 0;
}
2、友元函数是其他类的成员函数
cpp
#include <iostream>
using namespace std;
class A
{
private:
int A;
public:
print(){};
//声明类B的成员函数 person 是 类A 的友元函数
friend void B::person (int &x);
}
class B
{
private:
int B;
public:
person(int &x);
}
B::person(int &x)
{
//因为类B的成员函数person是类A的友元函数,所以看可以使用类A的成员变量age
cout << "age=" << p.age << endl;
}
int main ()
{
A p(22);
B q;
q.person(p);
return 0;
}
友元类
cpp
//时间类
class Time
{
friend class Date;
// 声明日期类为时间类的友元类,则在日期类中就直接访问Time类中的私有成员变量
public:
//成员函数的初始化列表
Time(int hour = 0, int minute = 0, int second = 0)
: _hour(hour)
, _minute(minute)
, _second(second)
{}
private:
int _hour;
int _minute;
int _second;
};
//日期类
class Date
{
public:
//成员函数的初始化列表
Date(int year = 1900, int month = 1, int day = 1)
: _year(year)
, _month(month)
, _day(day)
{}
void SetTimeOfDate(int hour, int minute, int second)
{
// 直接访问时间类私有的成员变量,因为日期类是时间类的友元类
_t._hour = hour;
_t._minute = minute;
_t._second = second;
}
private:
int _year;
int _month;
int _day;
Time _t;
};
优缺点总结
缺点:友元函数不是类的成员但是却具有成员的权限,可以访问类中受保护的成员,这破坏了类的封装特性和权限管控;
优点:可以实现类之间的数据共享;比如上面互为友元类,则可以互相访问对方受保护的成员;
总结:友元函数是一种破坏封装特性的机制,可以让程序员写代码更灵活,但是不能滥用;