友元函式和友元類

2021-12-30 00:12:04 字數 3951 閱讀 2300

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

友元函式

友元函式是可以直接訪問類的私有成員的非成員函式。它是定義在類外的普通函式,它不屬於任何類,但需要在類的定義中加以宣告,宣告時只需在友元的名稱前加上關鍵字friend,其格式如下:

friend 型別 函式名(形式引數);

友元函式的宣告可以放在類的私有部分,也可以放在公有部分,它們是沒有區別的,都說明是該類的乙個友元函式。

乙個函式可以是多個類的友元函式,只需要在各個類中分別宣告。

友元函式的呼叫與一般函式的呼叫方式和原理一致。

友元類

友元類的所有成員函式都是另乙個類的友元函式,都可以訪問另乙個類中的隱藏資訊(包括私有成員和保護成員)。

當希望乙個類可以訪問另乙個類的私有成員時,可以將該類宣告為另一類的友元類。定義友元類的語句格式如下:

friend class 類名;

其中:friend和class是關鍵字,類名必須是程式中的乙個已定義過的類。

例如,以下語句說明類b是類a的友元類:

class a

;經過以上說明後,類b的所有成員函式都是類a的友元函式,能訪問類a的私有成員和保護成員。

使用友元類時注意:

(1) 友元關係不能被繼承。

(2) 友元關係是單向的,不具有交換性。若類b是類a的友元,類a不一定是類b的友元,要看在類中是否有相應的宣告。

(3) 友元關係不具有傳遞性。若類b是類a的友元,類c是b的友元,類c不一定是類a的友元,同樣要看類中是否有相應的申明

友元函式

友元函式是能夠訪問類中的私有成員的成員函式。友元函式從語法上看,它與普通函式一樣,即在定義上和呼叫上與普通函式一樣。

友元關係不具對稱性。即 a 是 b 的友元,但 b 不一定是 a 的友元。 友元關係不具傳遞性。即 b 是 a 的友元,c 是 b 的友元,但是 c 不一定是 a 的友元。作用及特點友元提供了不同類的成員函式之間、類的成員函式與一般函式之間進行資料共享的機制。通過友元,乙個不同函式或另乙個類中的成員函式可以訪問類中的私有成員和保護成員。c++中的友元為封裝隱藏這堵不透明的牆開了乙個小孔,外界可以通過這個小孔窺視內部的秘密。友元的正確使用能提高程式的執行效率,但同時也破壞了類的封裝性和資料的隱藏性,導致程式可維護性變差。下面舉一例子說明友元函式的應用。

#include

#include

using namespace std;

class point

; void getxy();

friend double distance(point &a, point &b);

private:

double x, y;

};void point::getxy()

把這個定義與被定義為成員函式的操作符定義相比較:12

3456

boolstring::operator==(conststring

&rhs )const

你看到區別了嗎?我們注意到必須要修改函式定義內部對於string 類私有資料成員的引用方式。因為新的等於操作符是全域性函式,不是類成員函式,它不能直接引用string

的私有資料成員,它使用訪問成員函式size()和c_str()來獲得string

物件的大小,以及底層的c 風格字串。

另外一種可能的實現是把全域性「等於操作符」宣告為string 類的友元friend。通過把函式或操作符宣告為友元,乙個類可以授予這個函式或操作符訪問其非公有成員的權利。

友元宣告以關鍵字friend 開始,它只能出現在類定義中。因為友元不是授權類的成員,所以它不受其所在類的宣告區域public private 和protected 的影響。這裡我們選擇把所有友元宣告組織在一起並放在類頭之後:12

3456

78classstring;

string 類中的三個友元宣告把全域性域中宣告的三個過載的「比較操作符」(在上節介紹)宣告為string 類的友

元既然這些等於操作符已經被宣告為友元那麼它們的定義就可以直接引用string 的私有成員了。12

3456

78910

1112

13//

friend 操作符直接引用 string 的私有成員//

friend operators: refer to string private members directlybooloperator==(conststring

&str1,conststring

&str2 )inlinebooloperator==(conststring

&str,constchar*s )//

以下略有人可能會說在這種情況下由於c_str()和size()是內聯的它們提供了等價的效率,並且保留了成員封裝所以沒必要直接訪問_size 和_string ,這是對的。使用成員訪問函式而不是直接訪問成員,並不總是意味著它的效率較低。由於存在這些訪問函式,所以沒有必要把等於操作符宣告為string

類的友元。

那麼我們怎樣判斷乙個非類成員的操作符應該是類的友元還是應該使用成員訪問函式呢?一般來說,類的實現者應該盡量使得名字空間函式和訪問類內部表示的操作符的數目最小化。如果已經提供了訪問成員函式並且它們具有等同的效率那麼最好是使用這些成員函式,並且把名字空間操作符與類表示中的變化隔離開。但是如果類的實現者決定不為該類的某些私有成員提供訪問成員函式,而且名字空間操作符需要引用這些私有成員才能完成它們的操作,那麼就必須使用友元機制。

友元宣告的最常見用法是允許非成員的過載操作符訪問乙個視其為朋友的類的私有成員。原因是除了提供左和右運算元的對稱性外,可使非成員的過載操作符就像成員函式一樣能夠完全訪問乙個類的私有成員。

雖然友元宣告的主要用處是在過載操作符上,但是在某些情況下乙個名字空間函式,另乙個在此之前被定義的類的成員函式或者乙個完整的類必須宣告為友元。

在使乙個類成為另乙個類的友元時,友元類的成員函式,被賦予訪問授權類的非公有成員的權利。

下面我們將更詳細地了解函式而不是操作符的友元宣告。

乙個類必須把它希望與之建立友元關係的過載函式集中的每個函式都宣告為友元。例如1

2345

6789

externostream&

storeon( ostream &, screen & );externbitmap&

storeon( bitmap &, screen & );//

...classscreen;

如果乙個函式操縱兩個不同類型別的物件而且該函式需要訪問這兩個類的非公有成員,則這個函式可以被宣告為這兩個類的友元,或者作為乙個類的成員函式並宣告為另乙個類的友元讓我們來看一看怎樣做:如果我們決定乙個函式必須被宣告為兩個類的友元則友元宣告如下12

3456

78910

11classwindow;//

只宣告classscreen;classwindow;

如果我們決定該函式必須作為乙個類的成員函式並又是另乙個類的友元,則成員函式宣告和友元宣告如下:

classwindow;classscreen;classwindow;

只有當乙個類的定義已經被看到時它的成員函式才能被宣告為另乙個類的友元。這並不總是能夠做到的。

例如如果screen 類必須把window 類的成員函式宣告為友元,而window類必須把screen 類的成員函式宣告為友元。該怎麼辦呢?在這種情況下可以把整個window類宣告為screen 類的友元。

例如:123

456classwindow;classscreen;

screen 類的非公有成員現在可以被window 的每個成員函式訪問。

友元 友元函式 友元類和友元成員函式 C

有些情況下,允許特定的非成員函式訪問乙個類的私有成員,同時仍阻止一般的訪問,這是很方便做到的。例如被過載的操作符,如輸入或輸出操作符,經常需要訪問類的私有資料成員。友元 frend 機制允許乙個類將對其非公有成員的訪問權授予指定的函式或者類,友元的宣告以friend開始,它只能出現在類定義的內部,友...

友元 友元函式 友元類和友元成員函式 C

有些情況下,允許特定的非成員函式訪問乙個類的私有成員,同時仍阻止一般的訪問,這是很方便做到的。例如被過載的操作符,如輸入或輸出操作符,經常需要訪問類的私有資料成員。友元 frend 機制允許乙個類將對其非公有成員的訪問權授予指定的函式或者類,友元的宣告以friend開始,它只能出現在類定義的內部,友...

C 友元 友元函式 友元類和友元成員函式

有些情況下,允許特定的非成員函式訪問乙個類的私有成員,同時仍阻止一般的訪問,這是很方便做到的。例如被過載的操作符,如輸入或輸出操作符,經常需要訪問類的私有資料成員。友元 frend 機制允許乙個類將對其非公有成員的訪問權授予指定的函式或者類,友元的宣告以friend開始,它只能出現在類定義的內部,友...