友元简介:友元函数,友元类和友元成员函数

来源:互联网 发布:微信投票软件 编辑:程序博客网 时间:2024/06/09 17:53
友元简介:
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的关系。但是 遥控可以改变 电视机的状态,此种情况用友元来实现,更合适,即让遥控类作为电视机类的友元,可以更改其私有成员。

例子:
    
    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.类定义置后。(保证当一个类的定义中 使用另一个类的方法时,所用的方法在此定义之前,已声明)。
需小心排列各种声明和定义的顺序。

例:
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的类定义。
 
原创粉丝点击