友元为类外的函数提供了一种突破封装的方式,简单来说就是让类外能够破解private、protected型私有类型成员变量或函数,为其提供了便利。之前在讲流提取、流插入运算符函数重载的时候简单介绍了一下友元,大家可以来看一看这篇博客中,类外是如何能够调用重载函数的。C++基础——流插入提取运算符重载函数_。
- class Date
- {
-
- public:
- Date(int year = 1900, int month = 1, int day = 1)
- : _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;
- cin >> d;
- cout << d << endl;
- return 0;
- }
流插入和流提取运算符想要在类外进行运算符的重载,需要用到友元,让这两个函数在类内发布友元声明,这样类外就可以将其视为朋友,轻而易举的访问到Date类的非公有成员了。
假设类A想要访问类B的非公有成员,就需要在类B中存放类A的友元声明了,也是friend关键字+class+类名即可。
- 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;
- };
将Time类外的Date类在Time类内加上friend, Time类会视Date类为朋友,Date类可以访问Time类的私有成员,Date可以偷Time的家,而Time类不是Date的朋友,Time类不可以访问Date的私有成员。而在SetTimeOfDate函数中,成员变量_t就可以直接访问到Time类的非公有成员。
需要注意的是:使用友元会增加耦合度,破坏了封装,所以友元不宜多用。
将一个类定义在另一个类的内部,内部类是一个独立的类,它不属于外部类,更不能通过外部类去访问内部类成员。
示例代码,如下:
- class A
- {
- private:
- static int k;
- int h;
- public:
- class B // B天生就是A的友元,类B可以访问类A的成员,但类A不能访问类B的成员
- {
- public:
- void foo(const A& a)
- {
- cout << k << endl; //OK
- cout << a.h << endl;//OK
- }
- private:
- double _b;
- int _a;
- };
- };
-
- int A::k = 1;
-
- int main()
- {
- A aa;
- cout << sizeof(A) << endl;
- cout << sizeof(aa) << endl;
-
- cout << sizeof(A::B) << endl; //16字节
-
-
- A::B b;
- b.foo(A());
-
- return 0;
- }
由定义得,内部类不属于外部类,所以我写了两行行检测类A,类A对象存储大小的代码,发现:

结果都为4字节,即只存储了int h的大小,且静态成员变量在静态区,所以不进内存空间,那么类B中的a,b成员完全没有算进去。所以由此推断:这个内部类等价于是两个独立的类 。
但是若类B想要创建对象还是得通过类A才可以,毕竟类B在类A的内部 ~哈哈哈,没办法!
内部类天生就是是外部类的友元,也就是说,不需要在类A中发表类B的友元声明,类B也可以随意的访问类A的非公有成员!!!

