在類的外部,任何實例訪問類的 private 或 protected 成員都是被禁止的,這是出於安全性的考慮。但是很多時候,出於實用性的考慮,的確需要從外部訪問類的 private 或 protected 的成員,這可以在 C++ 中通過關鍵字 friend 來實現。
友元(friend)機制允許一個類將對其非公有成員(private 和 protected 成員)的訪問授予指定的函數或類。友元函數必須要在類的內部進行聲明,友元不是授予友元關系的那個類成員,出於編碼風格的考慮,通常將友元聲明橙組地放置在類定義的開頭或結尾處
一、全局函數作為友元
[cpp]
// Friend_Global.cpp
#include <iostream>
using namespace std;
class Base {
int value; // 私有成員
protected:
string str; // 保護成員
public:
Base(const string newStr, const int ii) :
str(newStr), value(ii) {}
friend void view(Base&); // 聲明friend的全局函數
};
void view(Base& b) { // 接受的是基類對象
cout << "string = " << b.str << endl
<< "value = " << b.value << endl;
return ;
}
int main() {
Base b("Base", 49);
view(b);
/*
// 任何實例,在類的外部試圖訪問
// 類的private或protected成員都是被禁止的
cout << "string = " << b.str << endl
<< "value = " << b.value << endl;
*/
return 0;
}
運行結果:
值得注意的是,使用friend關鍵字修飾的全局函數void view(Base& b)並非是Base類的成員函數,它僅僅是全局函數
二、其它類的成員函數成為友元
[cpp]
// Friend_Class.cpp
#include <iostream>
using namespace std;
class Y; // 因為在類X中的view函數中出現了Y,因此必須事先聲明類Y
class X {
public:
/*
參數類型聲明為指針,因為類Y的定義在下方,
在Y的定義之前,編譯器或許並不知道應該為Y的對象
分配多大的內存空間,而如果是Y*指針的話,編譯器
作了一次不完全的類型匹配,編譯器知道如何傳遞一個
地址,這一地址有具體的大小,而不管被傳遞的是什麼
對象,即使它還沒有完全知道這種對象類型的大小
雖然事實上傳遞對象也是可以的,但是在這種情況下,
傳遞一個對象的地址更為安全!
*/
void view(const Y*);
};
class Y {
int value; // 私有成員
protected:
string str; // 保護成員
public:
Y(const string newStr, const int ii) :
str(newStr), value(ii) {}
friend void X::view(const Y*); // 聲明friend的全局函數
};
void X::view(const Y* y) {
cout << "string = " << y->str << endl
<< "value = " << y->value << endl;
return ;
}
int main() {
Y y("Base", 49);
X x;
x.view(&y);
return 0;
}
運行結果: