友元类有以下两个特点:
(1)如果B声明成A的友元类,那么B可以访问A的protected、private成员。但是A不能访问B的protected、private成员。
(2)如果C继承B,C不能访问A的protected、private数据成员和函数,只能访问A的public成员。但是可以通过B的公共接口获取到A的protected、private信息。
友元函数有以下两个特点:
(1)定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。
(2)虽然友元函数的原型有在类的定义中出现,但是友元函数并不是成员函数。
现在参照以下代码深入分析:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
class Father;
class Mother;
class Father
{
public:
Father()
{
m_nAge = 1;
m_nWeChat = 1;
m_nSalary = 1;
}
~Father()
{
m_nAge = 0;
m_nWeChat = 0;
m_nSalary = 0;
}
friend class Mother; //Mother是Father的友元类,可以访问father的private、protected成员
friend void GetFatherSalary(Father& tFather); //友元函数,可以访问father的private、protected成员
public:
void PrintfAge()
{
printf("Father's age is 30.\n");
}
//void FatherGetMotherInfo(Mother &tMother)
//{
// printf("Father get mother info\n");
// //只能访问Mother的public成员
// printf("Mother public m_nSex : [%d]\n", tMother.m_nSex);
// printf("------------------\n\n");
//}
private:
void PrintfSalay()
{
printf("Father's salary is $2000.\n");
}
public:
int m_nAge; //年龄
protected:
int m_nWeChat; //微信
private:
int m_nSalary; //工资
};
class Mother
{
public:
Mother()
{
m_nSex = 2;
m_nQQ = 2;
m_nPayCard = 2;
}
~Mother()
{
m_nSex = 0;
m_nQQ = 0;
m_nPayCard = 0;
}
public:
void MotherGetFatherInfo(Father &tFather)
{
//Mother是Father的友元类,可以访问Father的public、protected、private成员和函数
printf("Father public m_nAge : [%d]\n", tFather.m_nAge);
printf("Father protected m_nWeChat : [%d]\n", tFather.m_nWeChat);
printf("Father private m_nSalary : [%d]\n", tFather.m_nSalary);
tFather.PrintfAge();
tFather.PrintfSalay();
}
public:
int m_nSex; //性别
protected:
int m_nQQ; //QQ
private:
int m_nPayCard; //工资卡
};
class Son : public Mother
{
public:
Son()
{
m_nGirlFriend = 3;
}
~Son()
{
m_nGirlFriend = 0;
}
public:
void SonGetFatherInfo(Father &tFather)
{
printf("Father public m_nAge : [%d]\n", tFather.m_nAge);
//友元关系不能被继承,所以没法访问Father的m_nWeChat、m_nSalary、PrintfSalay等protected和private成员、函数
//printf("Father protected m_nWeChat : [%d]\n", tFather.m_nWeChat);
//printf("Father private m_nSalary : [%d]\n", tFather.m_nSalary);
tFather.PrintfAge();
//tFather.PrintfSalay();
}
void SonGetFatherInfoByMother(Father& tFather)
{
MotherGetFatherInfo(tFather);//虽然自己获取不到Father私有信息,可以通过Mother获取Father私有信息
}
private:
int m_nGirlFriend;
};
void GetFatherSalary(Father &tFather)
{
//友元函数可以访问father的private、protected成员
printf("friend function: get father salary[%d]\n", tFather.m_nSalary);
printf("friend function: get father wechat[%d]\n", tFather.m_nWeChat);
}
int main()
{
Father tFather;
Mother tMother;
Son tSon;
printf("------------------\n");
printf("Mother begin get father info......\n");
tMother.MotherGetFatherInfo(tFather);
printf("------------------\n\n");
printf("------------------\n");
printf("Son begin get father info......\n");
tSon.SonGetFatherInfo(tFather);
printf("------------------\n\n");
printf("------------------\n");
printf("Son begin get father info by mother......\n");
tSon.SonGetFatherInfoByMother(tFather);
printf("------------------\n\n");
//通过友元函数访问
GetFatherSalary(tFather);
return 0;
}
程序运行结果如下:
在上述代码中:
(1)妈妈(Mother)是爸爸(Father)的友元类,那么爸爸在妈妈面前没有任何隐私可言,即妈妈可以访问爸爸的public年龄m_nAge、protected微信m_nWeChat、private工资m_nSalary,而爸爸只能访问妈妈的public性别m_nSex。
(2)儿子继承妈妈,注意的是不能将友元关系继承下来,试想本身友元已经破坏了类的封装特性了,假如友元关系能继承下来,类与类的关系就非常乱了,难以维护这么错综复杂的关系,所以儿子只是继承了妈妈public的成员,同时只能访问爸爸的public年龄m_nAge。但是儿子可以通过妈妈打听到爸爸的收入情况,即妈妈的public函数MotherGetFatherInfo。
(3)有一种情况,爸爸考虑个人隐私,没有将妈妈置为友元类,妈妈就在爸爸那边默默装了个监控,即友元函数void GetFatherSalary(Father &tFather)诞生了,妈妈就能通过GetFatherSalary偷偷监视爸爸的peotected微信和private工资。