1. 程式人生 > >C++友元函式和友元類用法詳解

C++友元函式和友元類用法詳解

在C++中,我們使用類對資料進行了隱藏和封裝,類的資料成員一般都定義為私有成員,成員函式一般都定義為公有的,以此提供類與外界的通訊介面。但是,有時需要定義一些函式,這些函式不是類的一部分,但又需要頻繁地訪問類的資料成員,這時可以將這些函式定義為該函式的友元函式。除了友元函式外,還有友元類,兩者統稱為友元。友元的作用是提高了程式的執行效率(即減少了型別檢查和安全性檢查等都需要時間開銷),但它破壞了類的封裝性和隱藏性,使得非成員函式可以訪問類的私有成員。

友元函式 : 
       友元函式是可以直接訪問類的私有成員的非成員函式。它是定義在類外的普通函式,它不屬於任何類,但需要在類的定義中加以宣告,宣告時只需在友元的名稱前加上關鍵字friend,其格式如下:
       friend 型別 函式名(形式引數);
       友元函式的宣告可以放在類的私有部分,也可以放在公有部分,它們是沒有區別的,都說明是該類的一個友元函式。
       一個函式可以是多個類的友元函式,只需要在各個類中分別宣告。
       友元函式的呼叫與一般函式的呼叫方式和原理一致。
友元類 : 
       友元類的所有成員函式都是另一個類的友元函式,都可以訪問另一個類中的隱藏資訊(包括私有成員和保護成員)。       
       當希望一個類可以存取另一個類的私有成員時,可以將該類宣告為另一類的友元類。定義友元類的語句格式如下:
       friend class 類名;
       其中:friend和class是關鍵字,類名必須是程式中的一個已定義過的類。

例如,以下語句說明類B是類A的友元類:
       class A
       {
              …
       public:
              friend class B;
              …
       };
       經過以上說明後,類B的所有成員函式都是類A的友元函式,能存取類A的私有成員和保護成員。

       使用友元類時注意:
             (1) 友元關係不能被繼承。 
             (2) 友元關係是單向的,不具有交換性。若類B是類A的友元,類A不一定是類B的友元,要看在類中是否有相應的宣告。
             (3) 友元關係不具有傳遞性。若類B是類A的友元,類C是B的友元,類C不一定是類A的友元,同樣要看類中是否有相應的申明
《windows環境多執行緒程式設計原理與應用》中解釋:
  如果將類的封裝比喻成一堵牆的話,那麼友元機制就像牆上了開了一個門,那些得
  到允許的類或函式允許通過這個門訪問一般的類或者函式無法訪問的私有屬性和方   
  法。友元機制使類的封裝性得到消弱,所以使用時一定要慎重。

友元類:

將外界的某個類在本類別的定義中說明為友元,那麼外界的類就成為本類的“朋  
   友”,那個類就可以訪問本類的私有資料了。
   class Merchant
      {
          private :
             int m_MyMoney;
             int m_MyRoom;
             … …
          Public:
             Friend class Lawyer;
             Int getmoney();
             … …
      };
      Class Lawyer
     {
        Private:
          … …
        Public:
         … …
     };
     只有你賦予某個類為你的友元時,那個類才有訪問你的私有資料的權利。說明一個函式為一個類的友元函式則該函式可以訪問此類的私有資料和方法。定義方法是在類的定義中,在函式名前加上關鍵字friend.

需要友元與友元的優缺點: 

       通常對於普通函式來說,要訪問類的保護成員是不可能的,如果想這麼做那麼必須把類的成員都生命成為public(共用的),然而這做帶來的問題遍是任何外部函式都可以毫無約束的訪問它操作它,c++利用friend修飾符,可以讓一些你設定的函式能夠對這些保護資料進行操作,避免把類成員全部設定成public,最大限度的保護資料成員的安全。 

        友元能夠使得普通函式直接訪問類的保護資料,避免了類成員函式的頻繁呼叫,可以節約處理器開銷,提高程式的效率,但所矛盾的是,即使是最大限度大保護,同樣也破壞了類的封裝特性,這即是友元的缺點,在現在cpu速度越來越快的今天我們並不推薦使用它,但它作為c++一個必要的知識點,一個完整的組成部分,我們還是需要討論一下的。 在類裡宣告一個普通數學,在前面加上friend修飾,那麼這個函式就成了該類的友元,可以訪問該類的一切成員。

        下面我們來看一段程式碼,看看我們是如何利用友元來訪問類的一切成員的:

#include <iostream> 
using namespace std; 
class Internet 
{ 
public: 
Internet(char *name,char *address) // 改為:internet(const char *name , const char *address)
{ 
strcpy(Internet::name,name); 
strcpy(Internet::address,address); 
} 
friend void ShowN(Internet &obj);   //友元函式的宣告 
public:              // 改為:private
char name[20]; 
char address[20]; 
}; 
void ShowN(Internet &obj)        //類外普通函式定義,訪問a物件的保護成員name,不能寫成,void Internet::ShowN(Internet &obj) 
{ 
cout<<obj.name<<endl;          //可訪問internet類中的成員
} 
void main() 
{ 
Internet a("谷歌","http://www.google.cn/";); 
ShowN(a); 
cin.get(); 
} 
      示例2:

      分別定義一個類A和類B ,各有一個私有整數成員變數通過建構函式初始化;類A有一個成員函式Show(B &b)用來列印A和B的私有成員變數,請分別通過友元函式和友元類來實現此功能。使用友元類 和 友元函式實現:

#include <iostream>

using namespace std;
class B;
class A;
void Show( A& , B& );

class B
{
private:
int tt;
friend class A;
friend void Show( A& , B& );

public:
B( int temp = 100):tt ( temp ){}

};

class A
{
private:
int value;
friend void Show( A& , B& );

public:
A(int temp = 200 ):value ( temp ){}

void Show( B &b )
{
  cout << value << endl;
  cout << b.tt << endl; 
}
};

void Show( A& a, B& b )
{
cout << a.value << endl;
cout << b .tt << endl;
}

int main()
{
A a;
B b;
a.Show( b );
Show( a, b );
      return 0;
}