友元简介:
C ++ 为了保证类的封装性,使私有部分和保护部分对外不可见,公有部分提供唯一的访问途径。(基类的保护部分在 public ,protected方式的派生类中,也对外提供访问途径,在派生类中访问权限同公有部分)。
但这样的限制太严格,以至于不适合特定的编程,因此,C ++ 提供了另一种形式的访问权限,即友元。使得可以访问友元所在类的私有部分和保护部分。友元与位于类的 public , private ,protected的位置无关,均可访问所在类的私有部分和保护部分。
友元在一定程度上破坏了类的封装性,但同时也是类的接口操作更加灵活。
友元分为 3 中:
1.友元函数
可以将单独一函数作为一个类的友元函数,使这个函数具有访问 后者私有成员和保护成员的能力。
例子:
C ++ 为了保证类的封装性,使私有部分和保护部分对外不可见,公有部分提供唯一的访问途径。(基类的保护部分在 public ,protected方式的派生类中,也对外提供访问途径,在派生类中访问权限同公有部分)。
但这样的限制太严格,以至于不适合特定的编程,因此,C ++ 提供了另一种形式的访问权限,即友元。使得可以访问友元所在类的私有部分和保护部分。友元与位于类的 public , private ,protected的位置无关,均可访问所在类的私有部分和保护部分。
友元在一定程度上破坏了类的封装性,但同时也是类的接口操作更加灵活。
友元分为 3 中:
- 1.友元函数
- 2.友元类
- 3.友元成员函数
1.友元函数
可以将单独一函数作为一个类的友元函数,使这个函数具有访问 后者私有成员和保护成员的能力。
例子:
class Tv
{
private:
int channel;
int mode;
protected:
int vol;
public:
....
friend void settings(int c, Tv& t) { t.channel = c; t.mode = c;} //直接访问对类对象的 私有成员和保护成员
}
2.友元类
将一个类声明为另一个类的友元,这样作为友元的类 就可以访问 后者的私有成员和保护成员了。(无论友元类声明在后一个类的公有部分还是 私有部分,其所在位置无关紧要)
使用场合:如 电视机与遥控的关系。不是 has - a 的关系,因为 一台遥控可以控制多个电视。同时更不是 a kind of的关系。但是 遥控可以改变 电视机的状态,此种情况用友元来实现,更合适,即让遥控类作为电视机类的友元,可以更改其私有成员。
例子:
将一个类声明为另一个类的友元,这样作为友元的类 就可以访问 后者的私有成员和保护成员了。(无论友元类声明在后一个类的公有部分还是 私有部分,其所在位置无关紧要)
使用场合:如 电视机与遥控的关系。不是 has - a 的关系,因为 一台遥控可以控制多个电视。同时更不是 a kind of的关系。但是 遥控可以改变 电视机的状态,此种情况用友元来实现,更合适,即让遥控类作为电视机类的友元,可以更改其私有成员。
例子:
class Tv
{
private:
int channel;
int mode;
protected:
int vol;
public:
void set_mode();
friend class Remote;
}
class Remote
{
private:
int mode;
public:
void set_mode(Tv &t) { t.set_mode(); } //#1
void set_vol(int c, Tv&t) {t.vol= c;} // #2 访问 类的保护成员
void set_chan(int c, Tv&t) {t.channel = c;} // #3 访问 类的私有成员
}
3.友元成员函数
亦可以将一个类的成员函数作为另一个类的友元函数,仅使类的这个成员函数具有访问后者私有成员和保护成员的能力,其他类成员无这个能力。
如上例中,
亦可以将一个类的成员函数作为另一个类的友元函数,仅使类的这个成员函数具有访问后者私有成员和保护成员的能力,其他类成员无这个能力。
如上例中,
class Remote
{
...
public:
void set_mode(Tv &t) { t.set_mode(); } //#1
.....
}
#
1
依然为使用Tv类的公有接口来实现功能。 #
2
,#
3
直接访问
私有部分和保护部分
,因此可只将 #
2
,#
3
的类成员函数声明为
Tv类的友元
,Remote类的其他成员 只用通过公有接口来访问Tv类。
这样做两个注意项: 需小心排列各种声明和定义的顺序。
1 .前向声明的使用。
2 .类定义置后。(保证当一个类的定义中 使用另一个类的方法时,所用的方法在此定义之前,已声明)。
这样做两个注意项: 需小心排列各种声明和定义的顺序。
1 .前向声明的使用。
2 .类定义置后。(保证当一个类的定义中 使用另一个类的方法时,所用的方法在此定义之前,已声明)。
例:
class Tv; //Note 1:前向声明 因为Note 2 处 用到Tv &t,需告诉编译器,此处Tv 为类
class Remote
{
private:
int mode;
public:
enum{Off, On};
enum{MinVal, MaxVal = 20};
enum{Antenna, Cable};
enum{TV, VCR};
public:
Remote(int m = TV):mode(m){}
void onoff(Tv &t); //Note 2: error #1 {t.onff();} 因为在此之前未见到Tv 类的 onoff()成员函数,所以此定义需后置
void vol_up(Tv &t);
void vol_down(Tv &t);
void channel_up(Tv &t);
void channel_down(Tv &t);
void set_mode(Tv &t);
void set_input(Tv &t);
void set_chan(Tv &t, int c);
};
class Tv
{
private:
int state;
int channel;
int maxchannel;
int mode;
int input;
int volume;
public:
friend void Remote::set_chan(Tv &t,int c); // Note:3 声明 友元成员函数
enum{Off, On};
enum{MinVal, MaxVal = 20};
enum{Antenna, Cable};
enum{TV, VCR};
Tv(int s = Off, int mc = 100):state(s),maxchannel(mc),volume(5),
input(TV),mode(Antenna),channel(1){}
bool ison()const {return (state== On ? TRUE:FALSE);}
void onoff() {state = (state == On ? Off:On);}
void vol_up();
void vol_down();
void channel_up();
void channel_down();
void set_mode() {mode = (mode == Antenna ? Cable:Antenna);}
void set_input() {input = (input == TV ? VCR : TV);}
void settings();
};
void Tv::vol_up()
{
if (volume == MaxVal)
{
volume = MinVal;
}
else
volume++;
}
void Tv::vol_down()
{
if (volume == MinVal)
{
volume = MaxVal;
}
else
volume--;
}
void Tv::channel_up()
{
if (channel == maxchannel)
{
channel = 1;
}
else
channel++;
}
void Tv::channel_down()
{
if (channel == 1)
{
channel = maxchannel;
}
else
channel--;
}
void Tv::settings()
{
cout<<"Tv is "<<(state== On ? "on":"off")<<endl;
if (state == On)
{
cout<<"channel volume mode input\n";
cout<<setw(7)<<channel<<setw(8)<<volume
<<setw(10)<<(mode== Antenna ?"Antenna":"cable")
<<setw(7)<<(input== TV ? "TV":"Cable")<<endl;
}
}
inline void Remote::onoff(Tv&t) {t.onoff();} //Note 4: Remote 类方法定义置于 Tv类方法声明之后
inline void Remote::vol_up(Tv&t) {t.vol_up();}
inline void Remote::vol_down(Tv&t) {t.vol_down();}
inline void Remote::channel_up(Tv&t) {t.channel_up();}
inline void Remote::channel_down(Tv&t) {t.channel_down();}
inline void Remote::set_mode(Tv&t) {t.set_mode();}
inline void Remote::set_input(Tv&t) {t.set_input();}
inline void Remote::set_chan(Tv&t, int c){t.channel= c;}
讨论此处使用的为
class Tv;
class Remote
{
}
class TV
{
}
的方法,能否交换次序?改为:
class Remote;
class Tv{};
class Remote{};
答案不能。 Tv 的声明有
friend void Remote::set_chan(Tv &t,int c); 而在此前未见到 Remote类的声明(即含有set_chan(Tv &t, int c); 这一成员函数)。因此,在Tv的类定义之前,需先见到Remote的类定义。