? 采用類的機制后實現了數據的隱藏與封裝,類的數據成員一般定義為私有成員,成員函數一 般定義為公有的,依此提供類與外界間的通信接口。但是,有時需要定義一些函數,這些函數不 是類的一部分,但又需要頻繁地訪問類的數據成員,這時可以將這些函數定義為該類的友元函數。 除了友元函數外,還有友元類,兩者統稱為友元。友元的作用是提高了程序的運行效率(即減少了類型和安全性檢查及調用的時間開銷),但它破壞了類的封裝性和隱藏性,使得非成員函數可 以訪問類的私有成員。
? 友元可以是一個函數,該函數被稱為友元函數;友元也可以是一個類,該類被稱為友元類。
一 同類對象間無私處
MyString::MyString(const MyString & other)
{
int len = strlen(other._str);
this->_str = new char[len+1];
strcpy(this->_str,other._str);
}
二 異類對象間有友元
友元目的本質,是讓其它不屬于本類的成員(全局函數,其它類的成員函數),成為類的成員而具備了本類成員的屬性。
友元函數
友元函數是可以直接訪問類的私有成員的非成員函數。它是定義在類外的普通函數,它不屬于任何類,但需要在類的定義中加以聲明,聲明時只需在友元的名稱前加上關鍵字 friend,其格式如下:
friend 類型 函數名(形式參數);
一個函數可以是多個類的友元函數,只需要在各個類中分別聲明。
全局函數作友元函數
#include <iostream>
#include <cmath>
using namespace std;
class Point
{
public:
Point(double xx, double yy)
{
x = xx;
y = yy;
}
void Getxy();
friend double Distance(Point &a, Point &b);
private:
double x, y;
};
void Point::Getxy()
{
cout << "(" << x << "," << y << ")" << endl;
}
double Distance(Point &a, Point &b)
{
double dx = a.x - b.x;
double dy = a.y - b.y;
return sqrt(dx * dx + dy * dy);
}
int main(void)
{
Point p1(3.0, 4.0), p2(6.0, 8.0);
p1.Getxy();
p2.Getxy();
double d = Distance(p1, p2);
cout << "Distance is" << d << endl;
return 0;
}
類成員函數作友元函數
#include <iostream>
#include <cmath>
using namespace std;
class Point;//前向聲明
//由于ManagePoint中的函數需要作為Point中的友元函數中,故ManagePoint需要先定義
class ManagePoint
{
public:
double Distance(Point &a, Point &b);
};
/*
若放在這里會報錯
double ManagePoint::Distance(Point &a, Point &b)
{
double dx = a.x - b.x;
double dy = a.y - b.y;
return sqrt(dx * dx + dy * dy);
}
*/
class Point
{
public:
Point(double xx, double yy)
{
x = xx;
y = yy;
}
void Getxy();
////將一個類的成員函數作為另一個類的友元函數時,函數名應該用該函數所屬的類名字加以限定。
friend double ManagePoint::Distance(Point &a, Point &b);
private:
double x, y;
};
//這里引用了類Point的私有成員x和y,故需要放在類Point的定義之后(若放在ManagePoint和Point之間,會報錯)
double ManagePoint::Distance(Point &a, Point &b)
{
double dx = a.x - b.x;
double dy = a.y - b.y;
return sqrt(dx * dx + dy * dy);
}
void Point::Getxy()
{
cout << "(" << x << "," << y << ")" << endl;
}
int main(void)
{
Point p1(3.0, 4.0), p2(6.0, 8.0);
p1.Getxy();
p2.Getxy();
ManagePoint mp;
double d=mp.Distance(p1,p2);
cout << "Distance is" << d << endl;
return 0;
}
說明:關于前向聲明
前向聲明,是一種不完全型(forward declaration)聲明,即只需提供類名(無需提供 類實現)即可。正因為是(incomplete type)功能也很有限:
- 不能定義類的對象。
- 可以用于定義指向這個類型的指針或引用。
- 用于聲明(不是定義),使用該類型作為形參類型或者函數的返回值類型。
友元類
友元類的所有成員函數都是另一個類的友元函數,都可以訪問另一個類中的隱藏信息(包 括私有成員和保護成員)。
當希望一個類可以存取另一個類的私有成員時,可以將該類聲明為另一類的友元類。定義 友元類的語句格式如下:
friend class 類名;
其中:friend 和 class 是關鍵字,類名必須是程序中的一個已定義過的類。
例如,以下語句說明類 B 是類 A 的友元類:
class A {
...
public:
friend class B;
...
};
經過以上說明后,類 B 的所有成員函數都是類 A 的友元函數,能存取類 A 的私有成員和 保護成員。
class A
{
public:
inline void Test()
{
}
private:
int x, y;
friend Class B;
};
class B
{
public:
inline void Test()
{
A a;
printf("x=%d,y=%d".a.x, a.y);
}
}
注意:這里友元類放置的位置沒有嚴格要求,相比于類類成員函數作友元函數。
論友元
聲明位置
友元聲明以關鍵字 friend 開始,它只能出現在類定義中。因為友元不是授權類的成員, 所以它不受其所在類的聲明區域 public private 和 protected 的影響。通常我們選擇把所有友元聲明組織在一起并放在類頭之后.
友元的利弊
友元不是類成員,但是它可以訪問類中的私有成員。友元的作用在于提高程序的運行效率, 但是,它破壞了類的封裝性和隱藏性,使得非成員函數可以訪問類的私有成員。不過,類的訪問權限確實在某些應用場合顯得有些呆板,從而容忍了友元這一特別語法現象。
注意事項
(1) 友元關系不能被繼承。
(2) 友元關系是單向的,不具有交換性。若類 B 是類A的友元,類A不一定是類 B的友元,要看在類中是否有相應的聲明。
(3) 友元關系不具有傳遞性。若類B是類A的友元,類C是B的友元,類C不一定是類A的友元,同樣要看類中是否有相應的申明