友元(友元函式、友元類和友元成員函式) C++
有些情況下,允許特定的非成員函式訪問一個類的私有成員,同時仍阻止一般的訪問,這是很方便做到的。例如被過載的操作符,如輸入或輸出操作符,經常需要訪問類的私有資料成員。
友元(frend)機制允許一個類將對其非公有成員的訪問權授予指定的函式或者類,友元的宣告以friend開始,它只能出現在類定義的內部,友元宣告可以出現在類中的任何地方:友元不是授予友元關係的那個類的成員,所以它們不受其宣告出現部分的訪問控制影響。通常,將友元宣告成組地放在類定義的開始或結尾是個好主意。
1、友元函式
友元函式是指某些雖然不是類成員函式卻能夠訪問類的所有成員的函式。類授予它的友元特別的訪問權,這樣該友元函式就能訪問到類中的所有成員。
#include <iostream> using namespace std; class A { public: friend void set_show(int x, A &a); //該函式是友元函式的宣告 private: int data; }; void set_show(int x, A &a) //友元函式定義,為了訪問類A中的成員 { a.data = x; cout << a.data << endl; } int main(void) { class A a; set_show(1, a); return 0; }
2、友元類
友元類的所有成員函式都是另一個類的友元函式,都可以訪問另一個類中的隱藏資訊(包括私有成員和保護成員)。當希望一個類可以存取另一個類的私有成員時,可以將該類宣告為另一類的友元類。
關於友元類的注意事項:
(1) 友元關係不能被繼承。
(2) 友元關係是單向的,不具有交換性。若類B是類A的友元,類A不一定是類B的友元,要看在類中是否有相應的宣告。
(3) 友元關係不具有傳遞性。若類B是類A的友元,類C是B的友元,類C不一定是類A的友元,同樣要看類中是否有相應的申明。
#include <iostream> using namespace std; class A { public: friend class C; //這是友元類的宣告 private: int data; }; class C //友元類定義,為了訪問類A中的成員 { public: void set_show(int x, A &a) { a.data = x; cout<<a.data<<endl;} }; int main(void) { class A a; class C c; c.set_show(1, a); return 0; }
3、友元成員函式
使類B中的成員函式成為類A的友元函式,這樣類B的該成員函式就可以訪問類A的所有成員了。
當用到友元成員函式時,需注意友元宣告和友元定義之間的相互依賴,在該例子中,類B必須先定義,否則類A就不能將一個B的函式指定為友元。然而,只有在定義了類A之後,才能定義類B的該成員函式。更一般的講,必須先定義包含成員函式的類,才能將成員函式設為友元。另一方面,不必預先宣告類和非成員函式來將它們設為友元。
#include <iostream>
using namespace std;
class A; //當用到友元成員函式時,需注意友元宣告與友元定義之間的互相依賴。這是類A的宣告
class B
{
public:
void set_show(int x, A &a); //該函式是類A的友元函式
};
class A
{
public:
friend void B::set_show(int x, A &a); //該函式是友元成員函式的宣告
private:
int data;
void show() { cout << data << endl; }
};
void B::set_show(int x, A &a) //只有在定義類A後才能定義該函式,畢竟,它被設為友元是為了訪問類A的成員
{
a.data = x;
cout << a.data << endl;
}
int main(void)
{
class A a;
class B b;
b.set_show(1, a);
return 0;
}
友元小結:
在需要允許某些特定的非成員函式訪問一個類的私有成員(及受保護成員),而同時仍阻止一般的訪問的情況下,友元是可用的。
優點:
可以靈活地實現需要訪問若干類的私有或受保護的成員才能完成的任務;
便於與其他不支援類概念的語言(如C語言、彙編等)進行混合程式設計;
通過使用友元函式過載可以更自然地使用C++語言的IO流庫。
缺點:
一個類將對其非公有成員的訪問許可權授予其他函式或者類,會破壞該類的封裝性,降低該類的可靠性和可維護性。
參考資料:
1、《C++ Prime》第4版 第12章類的友元小節