在本文中,您將學(xué)習(xí)在C ++中創(chuàng)建友元函數(shù)和友元類,并在程序中有效地使用它們。
非成員函數(shù)無(wú)法訪問(wèn)對(duì)象的私有或受保護(hù)的數(shù)據(jù)。
但是,有時(shí)這種限制可能迫使程序員編寫(xiě)冗長(zhǎng)而復(fù)雜的代碼。因此,C ++編程內(nèi)置了一種機(jī)制,可以從非成員函數(shù)訪問(wèn)私有或受保護(hù)的數(shù)據(jù)。
這是使用友元函數(shù)和友元類完成的。
如果將函數(shù)定義為友元函數(shù),則可以使用函數(shù)訪問(wèn)類的私有數(shù)據(jù)和受保護(hù)數(shù)據(jù)。
通過(guò)使用關(guān)鍵字friend,編譯器知道給定的函數(shù)是友元函數(shù)。
要訪問(wèn)數(shù)據(jù),應(yīng)該在類的內(nèi)部以關(guān)鍵字friend開(kāi)始聲明友元函數(shù)(可以是類內(nèi)部的任何地方,可以是private部分,也可以是public部分)。
class class_name { ... .. ... friend return_type function_name(argument/s); ... .. ... }
現(xiàn)在,您可以將友元函數(shù)定義為訪問(wèn)該類數(shù)據(jù)的普通函數(shù)。friend定義中未使用任何關(guān)鍵字。
class className { ... .. ... friend return_type functionName(argument/s); ... .. ... } return_type functionName(argument/s) { ... .. ... // 可以從這個(gè)位置訪問(wèn)className的私有和受保護(hù)數(shù)據(jù) //因?yàn)榇撕瘮?shù)是className的友元函數(shù)。 ... .. ... }
/* C ++程序演示友元函數(shù)的工作。*/ #include <iostream> using namespace std; class Distance { private: int meter; public: Distance(): meter(0) { } //友元函數(shù) friend int addFive(Distance); }; // 友元函數(shù)的定義 int addFive(Distance d) { //從非成員函數(shù)訪問(wèn)私有數(shù)據(jù) d.meter += 5; return d.meter; } int main() { Distance D; cout<<"距離: "<< addFive(D); return 0; }
輸出結(jié)果
距離: 5
這里,友元函數(shù)addFive()在Distance類中聲明。因此,可以從這個(gè)函數(shù)訪問(wèn)私有數(shù)據(jù)。
盡管此示例為您提供了有關(guān)友元函數(shù)概念的想法,但并未顯示任何有意義的用途。
當(dāng)您需要對(duì)兩個(gè)不同類的對(duì)象進(jìn)行操作時(shí),將有一種更有意義的用法。那時(shí),友元函數(shù)會(huì)非常有幫助。
你完全可以在不使用friend函數(shù)的情況下操作兩個(gè)不同類的對(duì)象,但是這個(gè)程序會(huì)很長(zhǎng),很復(fù)雜,很難理解。
#include <iostream> using namespace std; // 前置聲明 class B; class A { private: int numA; public: A(): numA(12) { } //友元函數(shù)聲明 friend int add(A, B); }; class B { private: int numB; public: B(): numB(1) { } // 友元函數(shù)聲明 friend int add(A , B); }; //函數(shù)add()是類A和B的友元函數(shù) //訪問(wèn)成員變量numA和numB int add(A objectA, B objectB) { return (objectA.numA + objectB.numB); } int main() { A objectA; B objectB; cout<<"Sum: "<< add(objectA, objectB); return 0; }
輸出結(jié)果
Sum: 13
在這個(gè)程序中,類A和B已經(jīng)將add()聲明為friend函數(shù)。因此,這個(gè)函數(shù)可以訪問(wèn)這兩個(gè)類的私有數(shù)據(jù)。
在這里,add()函數(shù)將兩個(gè)對(duì)象objectS和object的私有數(shù)據(jù)numA和numB相加,并將其返回給main函數(shù)。
為了使這個(gè)程序正常工作,應(yīng)該像上面的實(shí)例中所示的那樣,對(duì)一個(gè)類B進(jìn)行前置聲明。
這是因?yàn)槭褂靡韵麓a在class A中引用了class B的友元函數(shù):friend int add(A,B);
類似地,像一個(gè)友元函數(shù)一樣,一個(gè)類也可以使用關(guān)鍵字friend成為另一個(gè)類的友元類。例如:
... .. ... class B; class A { // class B 是 class A的友元類 friend class B; ... .. ... } class B { ... .. ... }
當(dāng)一個(gè)類成為另一個(gè)類的friend類(友元類)時(shí),這就意味著這個(gè)類的所有成員函數(shù)都是另一個(gè)類的友元函數(shù)。
在這個(gè)程序中,B類的所有成員函數(shù)都是A類的朋友函數(shù),因此B類的任何成員函數(shù)都可以訪問(wèn)A類的私有和受保護(hù)的數(shù)據(jù),但是A類的成員函數(shù)不能訪問(wèn)B類的數(shù)據(jù)。
如何實(shí)現(xiàn)classA與B互為友元,即A可以訪問(wèn)B的私有,B也可以訪問(wèn)A的私有呢?案例如下:
#include <iostream> using namespace std; //必須提前聲明class B不然編譯會(huì)報(bào)錯(cuò) class B; class A{ private: int a; public: friend class B; A(){ cout << "類A被構(gòu)造" << endl; a = 20; } ~A(){ cout << "類A被析構(gòu)" << endl; } void show(B & b); }; class B{ private: int b; public: friend class A; B(){ cout << "類B的構(gòu)造" << endl; b = 12; } ~B(){ cout << "類B被析構(gòu)" << endl; } void show(A &a){ cout << "a="<<a.a ; cout << " b=" <<b<<endl; } }; //函數(shù)不能放在class A 中,不然會(huì)編譯報(bào)錯(cuò) void A::show(B &b){ cout << "a="<<a ; cout << " b="<<b.b<< endl; } int main(){ A a; B b; a.show(b); b.show(a); return 0; }運(yùn)行結(jié)果:
類A被構(gòu)造 類B的構(gòu)造 a=20 b=12 a=20 b=12 類B被析構(gòu) 類A被析構(gòu)
互為友元類的做法就是,在class A中聲明friend class B;在classB 中聲明friend class A;
注意:類A中使用到了類B的地方必須在類B的聲明后定義,在類A中只能聲明。例如左邊類A中的show函數(shù),不能在類A中直接定義,只能放在類B的聲明之后定義。