C++学习随笔之十二:友元

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)。它通过提供新的类型类作用域避免名称混乱。包含类的成员函数可以创建和使用被嵌套类的对象;而仅当声明位于公有部分,才能将包含类的外面使用嵌套类,而且必须使用作用域解析操作符。

posted @ 2013-03-17 19:38  Jamy Cai  阅读(389)  评论(0编辑  收藏  举报