友元函數 :
友元函數是可以直接訪問類的私有成員的非成員函數。它是定義在類外的普通函數,它不屬於任何類,但需要在類的定義中加以聲明,聲明時只需在友元的名稱前加上關鍵字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.
《挑戰30天C/C++》這樣解釋:
在說明什麼是友元之前,我們先說明一下爲什麼需要友元與友元的缺點:
通常對於普通函數來說,要訪問類的保護成員是不可能的,如果想這麼做那麼必須把類的成員都生命成爲public(共用的),然而這做帶來的問題遍是任何外部函數都可以毫無約束的訪問它操作它,c++利用friend修飾符,可以讓一些你設定的函數能夠對這些保護數據進行操作,避免把類成員全部設置成public,最大限度的保護數據成員的安全。
友元能夠使得普通函數直接訪問類的保護數據,避免了類成員函數的頻繁調用,可以節約處理器開銷,提高程序的效率,但所矛盾的是,即使是最大限度大保護,同樣也破壞了類的封裝特性,這即是友元的缺點,在現在cpu速度越來越快的今天我們並不推薦使用它,但它作爲c++一個必要的知識點,一個完整的組成部分,我們還是需要討論一下的。
在類裏聲明一個普通數學,在前面加上friend修飾,那麼這個函數就成了該類的友元,可以訪問該類的一切成員。
下面我們來看一段代碼,看看我們是如何利用友元來訪問類的一切成員的
//程序作者:管寧
//站點:www.cndev-lab.com
//所有稿件均有版權,如要轉載,請務必著名出處和作者
#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) //函數定義,不能寫成,void Internet::ShowN(Internet &obj)
{
cout<<obj.name<<endl; //可訪問internet類中的成員
}
void main()
{
Internet a("中國軟件開發實驗室","www.cndev-lab.com");
ShowN(a);
cin.get();
}
上面的代碼通過友元函數的定義,我們成功的訪問到了a對象的保護成員name,友元函數並不能看做是類的成員函數,它只是個被聲明爲類友元的普通函數,所以在類外部函數的定義部分不能夠寫成void Internet::ShowN(Internet &obj),這一點要注意。
================================================================================
實例:
分別定義一個類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;
}