c++友元

c++友元

參考《c++ Primer Plus》 第6版15.1ios

C++控制對類對象私有部分的訪問,在外部沒法直接訪問類的私有或保護成員。一般,公有類方法提供惟一的訪問途徑。有時這種限制太嚴格,不適合特定的編程問題。因此C++提供了友元這種形式,經過讓函數或類成爲類的友元,能夠賦予該函數或類與類的成員函數具備相同的訪問權限。c++

友元的做用在於提升程序的運行效率(即減小了類型檢查和安全性檢查等都須要的時間開銷),可是,它破壞了類的封裝性和隱藏性,使得非成員函數能夠訪問類的私有成員。編程

友元有3種:

(1)友元函數安全

(2)友元類函數

(3)友元成員函數this

 

1.友元函數

在類定義體中由關鍵字friend加以修飾說明的非成員函數spa

#include <iostream>
using namespace std;
class Window
{
        public: Window(int x, int y, int h, int w)
                {   
                        X=x, Y=y, H=h, W=w;
                }   
                friend long Area(Window & WinObj); //在類中聲明出友員函數的原型
                int getH() 
                {   
                        return H;
                }   
                int getW()
                { return W;
                }   
        private: int X,Y,H,W;
};
long Area(Window & WinObj) //在類外定義出友員函數的函數體
{ 
        return (long)WinObj.H*WinObj.W;
}

//實現經過對象訪問類中的private成員,由於對窗口的面積的計算最簡單的方式應該是H*W。
int main()
{ 
        Window winA(10,10,300,300);
        cout <<"Window Area is "<< endl;
        cout <<"Window Area square: "<< Area(winA)<< endl;
        return 0;
}

運行結果:設計

Window Area is 
Window Area square: 90000

友員函數與成員函數在編程方面的不一樣點:
  ① 友員函數在類體內應該採用friend加以限定,但成員函數不須要。
  ② 友員函數體在類體外不須要採用"類名::"加以限定。
  ③ 調用它時不須要採用"對象名.成員名"方式,而是直接調用它。
  ④ 因爲友員函數不是成員函數,於是無this指針,在函數體中訪問對象中的成員時必須經過對象名(可將形參定義爲引用),而在成員函數體內能夠直接訪問成員數據。指針

註釋:code

類的友元函數是非成員函數,其訪問權限與成員函數相同。

 

2. 友元類

能夠將類做爲友元,友元類的全部方法均可以訪問原始類的私有成員和保護成員。

以下 friend class Remote; 聲明Remote爲Tv類的友元類:

//tv.h -- Tv and Remote classes
#ifndef TV_H_
#define TV_H_
class Tv
{
    public:
        friend class Remote; //Remote can access Tv private parts
        enum State{Off,On};
        enum {MinVal,MaxVal=20};
        enum {Antenna,Cable};
        enum {TV,DVD};
        Tv(int s=Off,int mc=125):state(s),volume(5),maxchannel(mc),channel(12),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 set_mode() {mode=(mode==Antenna)?Cable:Antenna;}
        void set_input() {input=(input==TV)?DVD:TV;}
        void settings() const; //display all settings
    private:
        int state;
        int volume;
        int maxchannel;
        int channel;
        int mode;
        int input;
};
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 set_chan(Tv & t,int c){t.channel=c;}
        void set_mode(Tv & t){t.set_mode();}
        void set_input(Tv & t){t.set_input();}
};

 

3. 友元成員函數

在Remote類中,只有set_channel(Tv & tv, int ch)方法直接訪問Tv類的私有成員,因此能夠選擇只讓這個方法成爲類的友元,而沒必要讓Remote整個類成爲友元。不過這麼作必須當心排列各類聲明和定義的順序。

讓Remote::set_channel()成爲Tv類的友元方法是,在Tv類中將其聲明爲友元:

//tvfm.h
#ifndef TVFM_H_
#define TVFM_H_
class Tv;
class Remote
{
    public:
        enum State{Off,on};
        enum {MinVal,MaxVal=20};
        enum {Antenna,Cable};
        enum {TV,DVD};
    private:
        int mode;
    public:
        Remote(int m=TV):mode(m) {}
        bool volup(Tv &t);
        bool voldown(Tv & t);
        void onoff(Tv & t);
        void chanup(Tv & t);
        void chandown(Tv & t);
        void set_mode(Tv & t);
        void set_input(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};
        enum {MinVal,MaxVal=20};
        enum {Antenna,Cable};
        enum {TV,DVD};
        Tv(int s=Off,int mc=125):state(s),volume(5),maxchannel(mc),channel(12),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 set_mode() {mode=(mode==Antenna)?Cable:Antenna;}
        void set_input() {input=(input==TV)?DVD:TV;}
        void settings() const; //display all settings
    private:
        int state;
        int volume;
        int maxchannel;
        int channel;
        int mode;
        int input;
};
//Remote methods as inline functions
inline bool Remote::volup(Tv & t){return t.volup();}
inline bool Remote::voldown(Tv & t){return t.voldown();}
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_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;}
#endif

 

爲何須要友員函數

  ① 在封裝和快速性兩方面合理選擇----OOP中類的主要優勢是能夠實現數據隱藏與保護,即不容許非成員函數對它訪問,這樣能夠提升數據使用的安全性。但在訪問數據的效率方面則降低(由於正常時應該經過public型的方法來訪問)。但在某些應用場合下,非成員函數體中須要經過對象名直接訪問類中的private成員,以達到高速高效率地訪問數據,這能夠經過友員函數來實現。
 
  ② 有些函數須要放在類的外面或者類設計完之後再加以補充的,此時可能不能設計爲類中的成員函數,可是又須要訪問類中的私有成員。

相關文章
相關標籤/搜索