C++友元详解
1.什么是友元
在一个类A中,将类B声明为友元类,则类B可以访问类A的私有成员和保护成员。另外,也可以将函数声明为友元函数。
2.什么时候用到友元
若不同的类之间某些共享数据成员,可以使用友元,简化类的设计。
3.友元类
友元类的声明:friend class 类名
示例如下:
对于电视和遥控器来说,都共享频道数据成员和开关操作,这时可以将遥控器声明为电视的友元类,则遥控器可以直接访问电视的数据成员,且一个遥控器可以控制多台电视,这则例子很好的体现了友元的特点。
tv.h
#ifndef TV_H_ #define TV_H_ class Tv { public : friend class Remote; enum State{off,on}; Tv(int s=off,int mc=125):state(s),maxchannel(mc),channel(2){} void onoff(){state=(state==on)?off:on;} void chanup(); void chandown(); void settings() const; private: int state; int maxchannel; int channel; }; class Remote{ public: Remote(){}; void onoff(Tv &t){t.onoff();}; void chanup(Tv &t){t.chanup();}; void chandown(Tv &t){t.chandown();}; void set_chan(Tv &t,int c){t.channel=c;}; };
tv.cpp
#include<iostream> #include "tv.h" void Tv::chanup() { if(channel<maxchannel){ channel++; } else{ channel = 1; } } void Tv::chandown() { if(channel>1){ channel--; } else{ channel = maxchannel; } } void Tv::settings() const { using std::cout; using std::endl; cout<<"Tv is "<<(state==on?"on":"off")<<endl; if(state==on) { cout<<"channel:"<<channel<<endl; } }
use_tv.cpp 可使用同一个遥控器控制多台不同的电视
#include<iostream> #include "tv.h" int main() { using std::cout; using std::endl; Tv s42; cout<<"Initing Tv s42......"<<endl; s42.settings(); s42.onoff(); s42.chanup(); cout<<"adjusted Tv s42....."<<endl; s42.settings(); Remote control; control.set_chan(s42,10); control.volup(s42); cout<<"settings after using remote......"<<endl; s42.settings(); getchar(); return 0; }
示例可以看出,若不使用友元,则必须将Tv类的私有部分设置为共有的,或者创建一个大型类来包含电视和遥控器。这种解决方法也无法反应,一个遥控器可以用于多台电视。
4.友元函数
从上例可以看出,Remote类只有set_chan方法使用到了Tv类的私有成员,因此我们可以让Remote::set_chan()成为Tv类的友元函数,而不必让整个类成为友元。
tvfm.h
#ifndef TV_H_ #define TV_H_ class Tv; class Remote{ public : enum State{off,on}; private: int mode; public: Remote(){}; void onoff(Tv &t); void chanup(Tv &t); void chandown(Tv &t); void set_chan(Tv &t,int c); }; class Tv { public : friend void Remote::set_chan(Tv &t,int c); enum State{off,on}; Tv(int s=off,int mc=125):state(s),maxchannel(mc),channel(2){} void onoff(){state=(state==on)?off:on;} void chanup(); void chandown(); void settings() const; private: int state; int maxchannel; int channel; }; inline void Remote::onoff(Tv &t){t.onoff();} inline void Remote::chanup(Tv &t){t.chanup();} inline void Remote::chandown(Tv &t){t.chandown();} inline void Remote::set_chan(Tv &t,int c){t.channel=c;} #endif
5.共同的友元
多个类需要访问同一个函数,则可以在这些类中将这个函数声明为友元函数。例如:有一个计数器函数counter,两个类A和B同时调用这个函数,则可以在类A和B中将函数counter声明为友元函数。
void counter() { //.... } class A { friend int counter(); } class B { friend int counter(); }
6.使用友元类时注意:
1) 友元关系不能被继承。
2)友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元。
3) 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元
参考资料:《C++ Primer.Plus》 pp.602-610