天天看點

十六、友元函數和友元類、友元函數和友元類注意事項

一、友元函數介紹

        一般情況下,非類成員函數是不能通路成員變量的。但是有時候我們為了提高程式運作效率,希望外部函數能直接通路類的成員變量。此時我們可以使用友元。友元是一種允許非類成員函數通路類的非公有成員的一種機制。可以把一個函數指定為類的友元,也可以把整個類指定為另一個類的友元。

二、友元函數

友元函數在類作用域外定義,但它需要在類體中進行說明,為了與該類的成員函數加以差別,定義的方式是在類中用關鍵字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的友元。