C++中的友元包括友元函数和友元类。友元函数在前面章节类的使用中已经知道了,现在主要讨论友元类
1.友元类:
前面已经将友元函数用于类的扩展接口中,类并非只能友元函数的,也可以将类作为友元,即友元类。
友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。
当希望一个类可以存取另一个类的私有成员时,可以将该类声明为另一类的友元类。定义友元类的语句格式如下:
friend class 类名;
其中:friend和class是关键字,类名必须是程序中的一个已定义过的类。
例如,以下语句说明类B是类A的友元类:
class A
{
…
public:
friend class B;
…
};
经过以上说明后,类B的所有成员函数都是类A的友元函数,能存取类A的私有成员和保护成员。
使用友元类时注意:
(1) 友元关系不能被继承。
(2) 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。
(3) 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明
下面是模拟电视机和遥控器的简单示例程序:
头文件tv.h:
#pragma once
#include <iostream>
using namespace std;
//电视类
class Tv
{
private:
int state;//on or off
int volume;// volume
int maxchannel;//maximum number of maxchannel
int channel;// current channel
int mode;//broadcast or cable
int input;//TV or VCR
public:
friend class Remote;// 遥控器类
enum{Off,On};
enum{MinVal,MaxVal = 20};
enum{Broadcast,Cable};
enum{TV,VCR};
Tv(int s = Off,int mc = 100):state(s),volume(5),
maxchannel(mc),channel(2),mode(Cable),input(TV){}
void OnOff(){state = (state==On)?Off:On;}
bool IsOn()const{return state == On;}
bool VolUp();
bool VolDown();
void ChanUp();
void ChanDown();
void SetMode(){mode =(mode == Broadcast)?Cable:Broadcast;}
void SetInput(){input =(input == TV)?VCR:TV;}
void Settings()const;//display all settings
};
//遥控器类
class Remote
{
private:
int mode;
public:
Remote(int m = Tv::TV):mode(m){}
bool VolUp(Tv & t){return t.VolUp();}
bool VolDown(Tv & t){return t.VolDown();}
void OnOff(Tv & t){t.OnOff();}
void ChanUp(Tv & t){t.ChanUp();}
void ChanDown(Tv & t){t.ChanDown();}
void SetMode(Tv & t){t.SetMode();}
void SetInput(Tv & t){t.SetInput();}
void SetChan(Tv & t,int c){t.channel = c;}
};
实现文件tv.cpp:
#include <iostream>
#include "tv.h"
using namespace std;
bool Tv::VolUp()
{
if(volume<MaxVal)
{
volume++;
return true;
}
else
return false;
}
bool Tv::VolDown()
{
if(volume>0)
{
volume--;
return true;
}
else
return false;
}
void Tv::ChanUp()
{
if(channel<maxchannel)
{
channel ++;
}
else
channel = 1;
}
void Tv::ChanDown()
{
if(channel>0)
{
channel--;
}
else
channel = maxchannel;
}
void Tv::Settings()const
{
cout <<"Tv is" << (state == Off? "Off":"On") <<endl;
if(state == On)
{
cout <<"Volume setting = "<<volume<<endl;
cout <<"Channel setting = "<<channel<<endl;
cout <<"Mode = "<<mode<<endl;
cout <<"Input = " <<input <<endl;
}
}
测试文件mian.cpp:
#include <iostream>
#include "tv.h"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
Tv tcl;
cout <<"Initial settings for tcl:"<<endl;
tcl.Settings();
tcl.OnOff();
tcl.ChanUp();
cout <<"Adjusted settings for tcl:"<<endl;
tcl.Settings();
Remote rmt;
rmt.SetChan(tcl,24);
rmt.VolUp(tcl);
cout <<"settings after by Remote:"<<endl;
tcl.Settings();
return 0;
}
友元成员函数:如果不需要一个类的所有方法的公有接口,可以选择仅让特定的类成员成为另一个类的友元,而不必让整个类成为友元。这样做药注意的是声明和定义的顺序。
如上面程序中让Remote::SetChan()成为Tv类的友元的方法是,在Tv类声明中将其声明为友元:
class Tv
{
public:
friend void Remote ::SetChan(Tv & t,int c);
};
不过若要使编译器知能够处理这个语句,必须让它知道Remote的定义,因此应将Remote类的定义放在Tv的定义前面,但是,SetChan方法中有Tv的参数,所以应将Tv的定义放在Remote定义之前,为了避开这种循环,采用前向声明:
class Tv;
class Remote{...};
class Tv{....};
能否想下面这样顺序呢?
class Remote;
class Tv{...};
class Remote{..};
答案是不能。(要知道为什么哦?)
2.嵌套类:
嵌套类,顾名思义,是一个类嵌套在另一个类中。在C++中,可以将类声明放在另一类中。在另一个类中声明的类被称为嵌套类(nested class)。它通过提供新的类型类作用域避免名称混乱。包含类的成员函数可以创建和使用被嵌套类的对象;而仅当声明位于公有部分,才能将包含类的外面使用嵌套类,而且必须使用作用域解析操作符。