C++ 友元
友元
在一个类A中,将类B声明为友元类,则类B可以访问类A的私有成员和保护成员。另外,也可以将函数声明为友元函数。
什么时候用到友元
若不同的类之间某些共享数据成员,可以使用友元,简化类的设计。
友元类
友元类的声明: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类的私有部分设置为共有的,或者创建一个大型类来包含电视和遥控器。这种解决方法也无法反应,一个遥控器可以用于多台电视。
友元函数
从上例可以看出,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
共同的友元
多个类需要访问同一个函数,则可以在这些类中将这个函数声明为友元函数。例如:有一个计数器函数counter,两个类A和B同时调用这个函数,则可以在类A和B中将函数counter声明为友元函数。
void counter() { //.... } class A { friend int counter(); } class B { friend int counter(); }
使用友元类时注意:
1) 友元关系不能被继承。
2)友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元。
3) 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元。
为什么友元函数必须在类内部声明?
因为编译器必须能够读取这个结构的声明以理解这个数据类型的大小、行为等方面的所有规则。有一条规则在任何关系中都很重要,那就是谁可以访问我的私有部分。