友元

友元機制容許一個類將對其非公有成員的訪問權授予指定的函數或類。
友元的聲明以關鍵字 friend 開始。它只能出如今類定義的內部。
友元聲明能夠出如今類中的任何地方:
友元不是授予友元關係的那個類的成員,因此它們不受聲明出現部分的訪問控制影響。
一般,將友元聲明成組地放在類定義的開始或結尾是個好主意。面試

友元關係:一個例子編程

想像一下,除了 Screen 類以外,還有一個窗口管理器,管理給定顯示器上的一組 Screen。
窗口管理類在邏輯上可能須要訪問由其管理的 Screen 對象的內部數據。
假定 Window_Mgr 是該窗口管理類的名字,Screen 應該容許 Window_Mgr 像下面這樣訪問其成員:函數

class Screen {
    // Window_Mgr members can access private parts of class Screen
    friend class Window_Mgr;
    // ...restofthe Screen class
};

/**
 * Window_Mgr 的成員能夠直接引用 Screen 的私有成員。
 * 例如,Window_Mgr 能夠有一個函數來重定位一個 Screen:
**/

Window_Mgr& Window_Mgr::relocate(Screen::index r, Screen::index c, Screen& s)
{
    // ok to refer to height and width
    s.height += r;
    s.width += c;
    return *this;
}

缺乏友元聲明時,這段代碼將會出錯:將不容許使用形參 s 的 height 和 width 成員。
由於 Screen 將友元關係授予 Window_Mgr,因此,Window_Mgr 中的函數均可以訪問 Screen 的全部成員。
友元能夠是普通的非成員函數,或前面定義的其餘類的成員函數,或整個類。
將一個類設爲友元,友元類的全部成員函數均可以訪問授予友元關係的那個類的非公有成員。this

使其餘類的成員函數成爲友元spa

若是不是將整個 Window_Mgr 類設爲友元,Screen 就能夠指定只容許 relocate 成員訪問:rest

class Screen {
    // Window_Mgrmust be defined before class Screen
    friend Window_Mgr& Window_Mgr::relocate(Window_Mgr::index,
                          Window_Mgr::index,                         Screen
&); // ...restofthe Screen class };

當咱們將成員函數聲明爲友元時,函數名必須用該函數所屬的類名字加以限定。code

友元聲明與做用域對象

爲了正確地構造類,須要注意友元聲明與友元定義之間的互相依賴。
在前面的例子中,類 Window_Mgr 必須先定義。
不然,Screen 類就不能將一個 Window_Mgr 函數指定爲友元。
然而,只有在定義類 Screen 以後,才能定義 relocate 函數
——畢竟,它被設爲友元是爲了訪問類 Screen 的成員。blog

更通常地講,必須先定義包含成員函數的類,才能將成員函數設爲友元。
另外一方面,沒必要預先聲明類和非成員函數來將它們設爲友元。作用域

友元聲明將已命名的類或非成員函數引入到外圍做用域中。
此外,友元函數能夠在類的內部定義,該函數的做用域擴展到包圍該類定義的做用域。

用友元引入的類名和函數(定義或聲明),能夠像預先聲明的同樣使用:

class X {
  friend class Y;
  friend void f() { /* ok to define friend function in the class body */ }
};
class Z {
  Y *ymem; // ok: declaration for class Y introduced by friend in X
  void g() { return ::f(); } // ok: declaration of f introduced by X
};


重載函數與友元關係

類必須將重載函數集中每個但願設爲友元的函數都聲明爲友元:

// overloaded storeOn functions
extern std::ostream& storeOn(std::ostream &, Screen &);
extern BitMap& storeOn(BitMap &, Screen &);
class Screen {
  // ostream version of storeOn may access private parts of Screen objects
  friend std::ostream& storeOn(std::ostream &, Screen &);
  // ...
};

類 Screen 將接受一個 ostream& 的 storeOn 版本設爲本身的友元。
接受一個 BitMap& 的版本對 Screen 沒有特殊訪問權。

 

/********* 面試中常見的有關友元的問題 *********/
Question:
什麼狀況下友元是有用的?討論使用友元的優缺點?

Answer:
在須要容許某些特定的非成員函數訪問同一個累的私有成員(以及被保護成員),
而同時仍阻止通常的訪問的狀況下,友元是有用的。

優勢: 能夠靈活地實現須要訪問若干累的私有以及受保護成員才能完成的任務;
便於與其餘不支持類概念的語言(C語言、彙編語言等)進行混合編程;
經過使用友元函數重載能夠更天然的使用C++語言的I/O流庫。

缺點: 一個類將對其非公有成員的訪問權授予其餘的函數或類, 會破快該類的封裝性,下降該類的可靠性和可維護性。

相關文章
相關標籤/搜索