一種共享數據方式--友元。友元是一種破壞類的封裝性獲取類的隱藏數據的方式。
如果有以下程序:
- class A
- {
- public:
- int Getx() { return x; }
- private:
- int x;
- };
- class B
- {
- public:
- void Set(int y);
- private:
- A a;
- };
上面就是類的組合的形式。類B中包含一個類A的對象作爲數據成員。但是類B的成員函數不能直接訪問類A的私有數據成員x。比如下面類B的成員函數Set的實現是不正確的:
void B::Set(int y)
{
a.x = y;
}
那麼怎樣實現B的成員函數直接訪問A的數據成員呢?C++提供了友元機制。
通過友元的方式,某個普通函數或者類的成員函數可以訪問某個類中的私有數據,這樣就等於在類的封裝的很好的外衣上剪開了一個小洞,外界可以通過這個小洞訪問到一些類內部的數據。友元提供了一種不同類或對象的成員函數之間、類的成員函數與普通函數之間共享數據的機制。它破壞了類的封裝性和類數據的隱藏性,但是又給我們進行軟件開發提供了很多方便,在我們實地進行軟件開發的時候可以自己在共享和封裝之間平衡一下,決定是否選擇使用友元,原則上儘量少使用或不使用友元,除非確實很大的提高了開發效率。
在一個類中聲明友元的方式是,用關鍵字friend把普通函數、其他類的成員函數或其他類聲明爲此類的友元,用friend聲明的元素就可以訪問此類的私有數據。如果友元是普通函數或是類的成員函數就叫做友元函數,如果友元是一個類則叫做友元類,友元類的所有成員函數均爲友元函數。
1.友元函數
友元函數是在類的聲明中用關鍵字friend修飾的普通函數或者其他類的成員函數。友元函數雖不是本類的成員函數,但在它的函數體中可以訪問該類對象的私有成員和保護成員。舉個例子:
- #include <iostream>
- #include <math.h>
- using namespace std;
- class Data //Data類聲明
- {
- public: //外部接口
- Data(int xx=0) { x=xx; }
- int GetX() { return x; }
- friend int Add(Data &a, Data &b);
- private: //私有數據成員
- int x;
- };
- int Add(Data &a, Data &b)
- {
- return a.x + b.x;
- }
- int main()
- {
- Data a(1);
- Data b(2);
- int sum = Add(a, b);
- cout<<"The sum is "<<sum<<endl;
- return 0;
- }
程序運行結果是:The sum is 3
在Data類中聲明友元函數Add時只給出了友元函數原型,友元函數Add的實現在類Data外。我們看到,在Add函數體中直接通過對象名訪問了Data類的私有成員x,這就是友元的強大作用。我們在類外用一般方式訪問x的話必須通過公共接口GetX來實現,若要訪問的私有成員很多或者要訪問的地方很多就要多次調用函數,對於我們寫代碼和程序運行都有效率上的損失,但是用友元也有個很大的缺點就是,如果私有數據x發生結構性的變化,那麼友元函數就要做相應的修改,所有調用友元函數的地方可能也要修改,這就降低了開發效率,所以是否要使用友元可以自己權衡。
上面例子中的友元函數是普通函數,這個函數也可以是其他類的成員函數,用法類似。
2.友元類
類也可以聲明爲另一個類的友元,就像友元函數那樣,這個作爲另一個類的友元的類就叫做友元類。如果一個類B是類A的友元類,則類B的所有成員函數都是類A的友元函數,都能訪問類A的私有成員和保護成員。友元類的聲明形式爲:
class A
{
...
friend class B; // 將類B聲明爲類A的友元類
...
}
上面聲明中,類B是類A的友元類,B的成員函數可以訪問類A的對象的私有成員和保護成員。
- class A
- {
- public:
- void Display() { cout<<x<<endl;}
- friend class B;
- private:
- int x;
- }
- class B
- {
- public:
- void Set(int i);
- void Display();
- private:
- A a;
- };
- void B::Set(int i)
- {
- a.x=i; // 因爲類B是類A的友元類,所以類B的成員函數可以訪問類A對象的私有成員
- }
- void B::Display()
- {
- a.Display();
- }
友元關係不能傳遞,如果類B是類A的友元,類C又是類B的友元,類C和類A如果沒有聲明則沒有友元關係,另外,友元關係是單向的,如果類B是類A的友元,類B的成員函數可以訪問類A對象的私有成員和保護成員,但是類A的成員函數不能訪問類B對象的私有成員和保護成員。
友元的知識大概就這些了,在使用的時候要綜合考慮封裝和共享之間的平衡,一般認爲還是要儘量少使用友元。