14.11 友元
类的主要特点之一是数据隐藏,即类的私有成员无法在类的外部(作用域之外)访问。但是,有时候需要在类的外部访问类的私有成员,怎么办?
解决方法是使用友元函数,友元函数是一种特权函数,c++允许这个特权函数访问私有成员。这一点从现实生活中也可以很好的理解:比如你的家,有客厅,有你的卧室,那么你的客厅是Public的,所有来的客人都可以进去,但是你的卧室是私有的,也就是说只有你能进去,但是呢,你也可以运行你的闺密好基友进去。程序员也可以把一个全局函数、某个类中的成员函数、甚至整个类声明为友元。
14.11.1 友元的语法
使用friend关键字声明友元。
friend关键字只出现在声明处,一个函数或者类作为了另一个类的友元 那么这个函数或类就可以直接访问 另一个类的私有数据。
友元 重要用在运算符重载上。
14.11.2 普通全局函数作为类的友元
#include <string>
using namespace std;
class Room
{
friend void visting01(Room &room);
private:
string bedRoom;//卧室
public:
string setingRoom;//客厅
public:
Room(string bedRoom,string setingRoom)
{
this->bedRoom = bedRoom;
this->setingRoom = setingRoom;
}
};
//普通全局函数
void visiting01(Room &room)
{
cout<<"访问了"<<room.setingRoom<<endl;
cout<<"访问了"<<room.bedRoom<<endl;
}
int main()
{
Room room("卧室","客厅");
visiting01(room);
return 0
}
14.11.3 类的某个成员函数作为另一个类的友元
class Room;//向前声明 只能说明类名称
class goodGay
{
public:
void visiting01(Room &room);
void visiting02(Room &room);
};
class Room
{
friend void goodGay::visiting02(Room &room);
private:
string bedRoom;//卧室
public:
string setingRoom;//客厅
public:
Room(string bedRoom, string setingRoom)
{
this->bedRoom=bedRoom;
this->setingRoom=setingRoom;
}
};
void goodGay::visiting01(Room &room)
{
cout<<"访问了"<<room.setingRoom<<endl;
//cout<<"访问了"<<room.bedRoom<<endl;
}
void goodGay::visiting02(Room &room)
{
cout<<"好基友张三访问了"<<room.setingRoom<<endl;
cout<<"好基友张三访问了"<<room.bedRoom<<endl;
}
int main()
{
Room room("卧室","客厅");
goodGay ob;
ob.visiting01(room);
ob.visiting02(room);
return 0;
}
14.11.4 整个类作为另一个类的友元
这个类的所有成员函数都可以访问另一个类的私有数据。
class Room;
class goodGay
{
public:
void visiting01(Room &room);
void visiting02(Room &room);
};
class Room
{
friend class goodGay;
private:
string bedRoom;//卧室
public:
string setingRoom;//客厅
public:
Room(string bedRoom, string setingRoom)
{
this->bedRoom=bedRoom;
this->setingRoom=setingRoom;
}
};
void goodGay::visiting01(Room &room)
{
cout<<"访问了"<<room.setingRoom<<endl;
cout<<"访问了"<<room.bedRoom<<endl;
}
void goodGay::visiting02(Room &room)
{
cout<<"好基友张三访问了"<<room.setingRoom<<endl;
cout<<"好基友张三访问了"<<room.bedRoom<<endl;
}
int main()
{
Room room("卧室","客厅");
goodGay ob;
ob.visiting01(room);
ob.visiting02(room);
return 0;
}
14.11.5 友元的注意事项
- 友元关系不能被继承
- 友元关系是单向的,类A是类B的朋友,但类B不一定是类A的朋友。
- 友元关系不具有传递性。类B是类A的朋友,类C是类B的朋友,但类C不一定是类A的朋友。
14.11.6 友元的案例(遥控器的类)
请编写电视机类,电视机有开机和关机状态,有音量,有频道,提供音量操作的方法,频道操作的方法。由于电视机只能逐一调整频道,不能指定频道,增加遥控类,遥控类除了拥有电视机已有的功能,在增加根据输入调台功能。
提示:遥控器可作为电视机类的友元类
#include <iostream>
using namespace std;
class TV;
//遥控器的类作为TV的友元
class Remote
{
private:
TV *p;
public:
Remote(TV *p)
{
this->p = p;
}
void offOrOn(void);
void upVolume(void);
void downVolume(void);
void upChannel(void);
void downChannel(void);
void showTv(void);
void setChannel(int channel);
};
class TV
{
friend class Remote;
enum{OFF,ON};
enum{minVol, maxVol=10};
enum{minChan,maxChan=25};
private:
int state;
int volume;
int channel;
public:
TV()
{
state = OFF;
volume = minVol;
channel = minChan;
}
void offOrOn(void);
void upVolume(void);
void downVolume(void);
void upChannel(void);
void downChannel(void);
void showTv(void);
};
int main()
{
TV tv;
Remote re(&tv);
re.offOrOn();
re.upVolume();
re.upVolume();
re.setChannel(10);
re.showTv();
return 0;
}
void TV::offOrOn()
{
state = (state==OFF?ON:OFF);
}
void TV::upVolume()
{
if(volume == maxVol)
{
cout<<"音量已经最大"<<endl;
return;
}
volume++;
}
void TV::downVolume()
{
if(volume == minVol)
{
cout<<"音量已经最小"<<endl;
return;
}
volume--;
}
void TV::upChannel()
{
if(channel == maxChan)
{
cout<<"频道已经最大"<<endl;
return;
}
channel++;
}
void TV::downChannel()
{
if(channel == minChan)
{
cout<<"频道已经最小"<<endl;
return;
}
channel--;
}
void TV::showTv()
{
cout<<"当前电视机的状态:"<<(state==OFF?"关":"开")<<endl;
cout<<"当前电视机的音量:"<<volume<<endl;
cout<<"当前电视机的频道:"<<channel<<endl;
}
void Remote::offOrOn()
{
p->offOrOn();
}
void Remote::upVolume()
{
p->upVolume();
}
void Remote::downVolume()
{
p->downVolume();
}
void Remote::upChannel()
{
p->upChannel();
}
void Remote::downChannel()
{
p->downChannel();
}
void Remote::showTv()
{
p->showTv();
}
void Remote::setChannel(int channel)
{
if(channel>=TV::minChan && channel<=TV::maxChan)
{
p->channel = channel;
}
else {
cout<<"频道"<<channel<<"不在有效范围内"<<endl;
}
}