友元提供了不同類的成員函數之間、類的成員函數與一般函數之間進行數據共享的機制。通過友元,一個不同函數或另一個類中的成員函數可以訪問類中的私有成員和保護成員。c++中的友元為封裝隱藏這堵不透明的牆開了一個小孔,外界可以通過這個小孔窺視內部的秘密。
友元的正確使用能提高程序的運行效率,但同時也破壞了類的封裝性和數據的隱藏性,導致程序可維護性變差。
友元函數是可以直接訪問類的私有成員的非成員函數。它是定義在類外的普通函數,它不屬於任何類,但需要在類的定義中加以聲明,聲明時只需在友元的名稱前加上關鍵字friend,其格式如下:
友元函數的聲明可以放在類的私有部分,也可以放在公有部分,它們是沒有區別的,都說明是該類的一個友元函數。
一個函數可以是多個類的友元函數,只需要在各個類中分別聲明。
友元函數的調用與一般函數的調用方式和原理一致。
友元類 :
友元類的所有成員函數都是另一個類的友元函數,都可以訪問另一個類中的隱藏信息(包括私有成員和保護成員)。
當希望一個類可以存取另一個類的私有成員時,可以將該類聲明為另一類的友元類。定義友元類的語句格式如下:
friend class 類名;
其中:friend和class是關鍵字,類名必須是程序中的一個已定義過的類。
1: #include <iostream>
2: using namespace std;
3:
4: class Radius
5: {
6: friend class Circle; //聲明Circle為Radius的友元類
7: friend void Show_r(Radius &n); //聲明Show_r為友元函數
8: public:
9: Radius(int x)
10: {
11: r = x;
12: }
13: ~Radius()
14: {
15: }
16:
17: private:
18: int r;
19: };
20:
21: void Show_r(Radius &n)
22: {
23: cout<<"圓的半徑為: "<<n.r<<endl; //調用Radius對象的私有成員變量r
24: }
25:
26: class Circle
27: {
28: public:
29: Circle() {}
30: ~Circle(){}
31: double area(Radius a)
32: {
33: s = a.r * a.r * 3.1415926; //調用Radius對象的私有成員變量r
34: return s;
35: }
36: private:
37: double s;
38: };
39:
40: int main(int argc, char *argv[])
41: {
42: Radius objRadius(9);
43: Circle objCircle;
44:
45: Show_r( objRadius );
46: cout<<"面積為:"<<objCircle.area(objRadius)<<endl;
47:
48: return 0;
49: }
被聲明兩個類的友元聲明
如果我們決定一個函數必須被聲明為兩個類的友元則友元聲明如下
1: class Window; // 只聲明
2:
3: class Screen
4:
5: {
6:
7: friend bool is_equal( Screen &, Window & );
8:
9: // ...
10:
11: };
12:
13: class Window
14:
15: {
16:
17: friend bool is_equal( Screen &, Window & );
18:
19: // ...
20:
21: };
作為一個類的函數又是另一個類的友元
如果我們決定該函數必須作為一個類的成員函數並又是另一個類的友元,則成員函數聲明和友元聲明如下:
1: class Window;
2:
3: class Screen
4:
5: {
6:
7: public:
8:
9: // copy 是類 Screen 的成員
10:
11: Screen& copy( Window & );
12:
13: // ...
14:
15: };
16:
17: class Window
18:
19: {
20:
21: // copy 是類 Window 的一個友元
22:
23: friend Screen& Screen::copy( Window & );
24:
25: // ...
26:
27: };
只有當一個類的定義已經被看到時它的成員函數才能被聲明為另一個類的友元。這並不總是能夠做到的。
例如如果Screen 類必須把Window 類的成員函數聲明為友元,而Window類必須把Screen 類的成員函數聲明為友元。該怎么辦呢?在這種情況下可以把整個Window類聲明為Screen 類的友元。
例如:
1: class Window;
2:
3: class Screen
4:
5: {
6:
7: friend class Window;
8:
9: // ...
10:
11: };
Screen 類的非公有成員現在可以被Window 的每個成員函數訪問。
使用友元類時注意:
(1) 友元關系不能被繼承。
(2) 友元關系是單向的,不具有交換性。若類B是類A的友元,類A不一定是類B的友元,要看在類中是否有相應的聲明。
(3) 友元關系不具有傳遞性。若類B是類A的友元,類C是B的友元,類C不一定是類A的友元,同樣要看類中是否有相應的申明