1.友元函数
什么是友元函数?
类的友元函数可直接访问类中的私有成员变量,该函数是定义在类外的普通函数,不属于任何类,需要在类中加friend关键字声明。
比如我们在重载自定义类型输入输出操作符时就需要将操作符重载函数声明为友元函数:
class Date
{
//此处就是友元函数的声明
friend ostream& operator<<(ostream& out,const Date& d);
friend istream& operator>>(istream& in, Date& d);
public:
Date(int year, int month, int day)
:_year(year)
, _month(month)
, _day(day)
{
}
private:
int _year;
int _month;
int _day;
};
ostream& operator<<(ostream& out,const Date& d)
{
out << d._year << "-" << d._month << "-" << d._day << endl;
return out;
}
istream& operator>>(istream& in, Date& d)
{
in >> d._year >> d._month >> d._day;
return in;
}
友元函数的作用?
为什么重载自定义类型输入输出操作符时,要在类外定义?
如果在类中定义输入输出操作符重载函数,那么隐含的this指针是第一个形参,使用该操作符时会出现如下问题:
int main()
{
Date d1;
d1<<cout; //重载的 “<<” 只能这样使用
return 0;
}
显然,上述写法不符合使用习惯,究其原因,是因为在类中定义的函数,第一个参数肯定是隐含的this指针,所以在使用重载的操作符时,操作符的位置要在对象后面,要解决这一问题,就要将cout、cin作为第一个参数。
因此,这两个运算符的重载函数要在类外定义。
此时又产生了一个问题,类外定义的函数并不能访问类对象的私有成员变量。所以这里需要把运算符重载函数声明为该类的友元函数。
2.友元类
一个类需要访问另一个类的私有成员变量,就把该类声明为类一个类的友元类。
class Time
{
friend class Date; //声明友元类
public:
Time(int hour = 3, int minute = 10, int second = 45)
: _hour(hour)
, _minute(minute)
, _second(second)
{
}
private:
int _hour;
int _minute;
int _second;
};
class Date
{
public:
Date(int year = 2021, int month = 6, int day = 1)
:_year(year)
, _month(month)
, _day(day)
, _time()
{
}
//要访问自定义类型Time中的私有成员变量,就要让Date类成为Time类的友元类
void setTime(int hour,int minute,int second)
{
_time._hour = hour;
_time._minute = minute;
_time._second = second;
}
private:
int _year;
int _month;
int _day;
Time _time;
};
int main()
{
Date d1;
d1.setTime(11, 11, 11);
return 0;
}
注:
一个函数可以被声明为多个类的友元函数,一个类也可以被声明为多个类的友元类
友元关系不能传递
友元函数没有this指针!
友元的缺点:破坏了封装性!
3.内部类
类B定义在类A中,B天生就是A的友元类,B可以直接访问A的static、枚举成员,B访问A的普通私有成员变量需要A的对象。
class A
{
public:
A(int a2 = 99)
:_a2(a2)
{}
class B
{
public:
void Print(const A& a)
{
cout << "a1 = " << _a1 << endl; //直接访问外部类的私有成员变量
cout << "a2 = " << a._a2 << endl; //通过外部类对象访问外部类普通私有成员变量
}
private:
int _b;
};
private:
static int _a1;
int _a2;
};
int A::_a1 = 999;
int main()
{
A::B bb;
bb.Print(A());
return 0;
}