一、友元函數介紹
一般情況下,非類成員函數是不能通路成員變量的。但是有時候我們為了提高程式運作效率,希望外部函數能直接通路類的成員變量。此時我們可以使用友元。友元是一種允許非類成員函數通路類的非公有成員的一種機制。可以把一個函數指定為類的友元,也可以把整個類指定為另一個類的友元。
二、友元函數
友元函數在類作用域外定義,但它需要在類體中進行說明,為了與該類的成員函數加以差別,定義的方式是在類中用關鍵字friend說明該函數,格式如下: friend 類型 友元函數名(參數清單); 比如我們定義了一個Point類,我們希望提供一個函數計算兩點之間的距離。我們有兩種選擇,可以使用成員函數如:Point a;Point b; a.Distance(b);但是這樣不太直覺,因為我們比較習慣傳入兩個Point對象,傳回它們的Distance。例子如下:
#include <math.h>
#include <iostream>
using namespace std;
class Point
{
<span style="white-space:pre"> </span>friend double Distance(const Point& p1, const Point& p2);
public:
<span style="white-space:pre"> </span>Point(int x, int y);
private:
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>int x_;
<span style="white-space:pre"> </span>int y_;
};
Point::Point(int x, int y) : x_(x), y_(y)
{
}
double Distance(const Point& p1, const Point& p2)
{
<span style="white-space:pre"> </span>double dx = p1.x_ - p2.x_;
<span style="white-space:pre"> </span>double dy = p1.y_ - p2.y_;
<span style="white-space:pre"> </span>return sqrt(dx*dx + dy*dy);
}
int main(void)
{
<span style="white-space:pre"> </span>Point p1(3, 4);
<span style="white-space:pre"> </span>Point p2(6, 9);
<span style="white-space:pre"> </span>cout<<Distance(p1, p2)<<endl;
<span style="white-space:pre"> </span>return 0;
}
注意:友元函數必須有一個參數是友元類的指針或引用。這是理所當然的,既然是類的友元函數,必須要通路類的成員,而通路類的成員要有一個該類的指針或引用參數。(想一想為什麼必須是指針或引用?) 友元函數注意事項:
- 友元函數不是類的成員函數。在函數體中通路對象的成員,必須用對象名加運算符“.”加對象成員名(指針用->)。但友元函數可以通路類中的所有成員(公有的、私有的、保護的),一般函數隻能通路類中的公有成員。
- 友元函數不受類中的通路權限關鍵字限制。可以把它放在類的公有、私有、保護部分,但結果一樣。
- 某類的友元函數的作用域并非該類作用域。如果該友元函數是另一類的成員函數,則其作用域為另一類的作用域,否則與一般函數相同。
- 友元函數破壞了面向對象程式設計類的封裝性。是以友元函數如不是必須使用,則盡可能少用。或者用其他手段保證封裝性。
三、友元類 如果某類B的成員函數會頻繁的存取另一個類A的資料成員, 而A的資料成員的Private/Protectd限制造成B存取的麻煩, B隻能通過A的Public的成員函數進行間接存取,可以把B做成A類的友元類,即A類向B類開發其Private/Protectd内容, 讓B直接存取。 友元類:一個類可以作另一個類的友元 友元類的所有成員函數都是另一個類的友元函數 友元類的聲名:friend class 類名; 例子如下(類B能通路類A的所有私有成員):
#include <iostream>
using namespace std;
class A
{
friend class B ;
public :
void Display() { cout << x << endl ; } ;
private :
int x ;
} ;
class B
{
public :
void Set ( int i ) { Aobject.x = i ; } //通過類成員通路A的私有成員
void Display () { Aobject.Display () ; }
private :
A Aobject ;
};
int main()
{
B Bobject ;
Bobject.Set(100) ;
Bobject.Display() ;
return 0;
}
友元類注意事項:
- 友元關系是單向的。B是A的友元類,但是B不是A的友元類。(A把B當成好朋友,但是B不把A當做好朋友)
- 友元關系不能被傳遞。B是A的友元,A是C的友元。那麼B不是C的友元。
- 友元關系不能被繼承。B是A的友元,C繼承了B,那麼B不是C的友元。