概述:
1. 為什麼要使用友元?
通常對於普通函數來說,要訪問類的保護成員是不可能的,如果想這麼做那麼必須把類的成員都生命成為 public( 共用的) ,然而這做帶來的問題遍是任何外部函數都可以毫無約束的訪問它操作它;另一種方法是利用 C++ 的 friend 修飾符,可以讓一些你設定的函數能夠對這些私有或保護數據進行操作。
2. 使用友元有哪些缺點?
使用友元的同時也破壞了類的封裝特性,這即是友元最大的缺點。當對外聲明為友元後,你的所有細節全部都暴露給了對方。
就好像你告訴你朋友你很有錢這個密秘,進而又把你有多少錢,多少古董,多少家產,多少小妾等等所有的家底全給他說了。
3. 友元怎樣理解?
定一個友元函數,或是友元類,就是告訴對方:我的所有元素對你是開放的。這種 friend 是建立在灰常灰常灰常信任對方的基礎上的。
一. 普通函數做為類的一個友元函數
在類裡聲明一個普通函數,在前面加上 friend 修飾,那麼這個函數就成了該類的友元。
這時這個普通函數可以訪問該類的一切成員。
代碼如下:
[cpp] #include <iostream >
using namespace std;
class MyClass
{
public :
MyClass(string name)
{
m_name = name;
}
//聲明一個友元函數
friend void Display(MyClass &mycalss);
Protected:
string m_name;
};
//定義這個友元函數
//寫成 void MyClass::Display(MyClass &mycalss)
void Display(MyClass &mycalss)
{
cout << "Access Protected data : "<< mycalss.m_name << endl;
}
//測試
int main(int argc,char* argv[])
{
MyClass test("Class A");
Display(test);
return 0;
}
#include <iostream >
using namespace std;
class MyClass
{
public :
MyClass(string name)
{
m_name = name;
}
//聲明一個友元函數
friend void Display(MyClass &mycalss);
Protected:
string m_name;
};
//定義這個友元函數
//寫成 void MyClass::Display(MyClass &mycalss)
void Display(MyClass &mycalss)
{
cout << "Access Protected data : "<< mycalss.m_name << endl;
}
//測試
int main(int argc,char* argv[])
{
MyClass test("Class A");
Display(test);
return 0;
}說明:
1. 聲明這個友元函數可以在任何地方,可以在 public、protected 當然也可以在 privated 裡。
2. 在這個友元函數裡,你可以訪問這個類裡的所有的成員,所有的成員函數,而不管它是不是 public、protected 或 privated 的。
3. 定義友元函數時,不能寫成 void MyClass::Display(MyClass &mycalss) 這點要注意。
二. 一個普通函數可以是多個類的友元函數
在每個類裡面都有一個友元函數的聲明,聲明可以有多個,但定義只能有一個。
代碼如下:
[cpp] #include <iostream >
using namespace std;
class MyClass_B;
class MyClass_A
{
public:
MyClass_A(string name)
{
m_name = name;
}
//聲明一個友元函數
friend void Display(MyClass_A &myA, MyClass_B &myB);
private:
string m_name;
};
class MyClass_B
{
public:
MyClass_B(string name)
{
m_name = name;
}
//注意,又聲明一個友元函數
friend void Display(MyClass_A &myA, MyClass_B &myB);
private:
string m_name;
};
//定義這個友元函數
void Display(MyClass_A &myA, MyClass_B &myB)
{
cout << "MyClass A : "<< myA.m_name << endl;
cout << "MyClass B : "<< myB.m_name << endl;
}
//測試代碼
int main(int argc,char* argv[])
{
MyClass_A testA("Class A");
MyClass_B testB("Class A");
Display(testA, testB);
return 0;
}
#include <iostream >
using namespace std;
class MyClass_B;
class MyClass_A
{
public:
MyClass_A(string name)
{
m_name = name;
}
//聲明一個友元函數
friend void Display(MyClass_A &myA, MyClass_B &myB);
private:
string m_name;
};
class MyClass_B
{
public:
MyClass_B(string name)
{
m_name = name;
}
//注意,又聲明一個友元函數
friend void Display(MyClass_A &myA, MyClass_B &myB);
private:
string m_name;
};
//定義這個友元函數
void Display(MyClass_A &myA, MyClass_B &myB)
{
cout << "MyClass A : "<< myA.m_name << endl;
cout << "MyClass B : "<< myB.m_name << endl;
}
//測試代碼 www.2cto.com
int main(int argc,char* argv[])
{
MyClass_A testA("Class A");
MyClass_B testB("Class A");
Display(testA, testB);
return 0;
}
同樣的,這個友元函數,可以訪問這兩個類的所有元素。
三. 一個類的成員函數也可以是另一個類的友元
從而可以使得一個類的成員函數可以操作另一個類的數據成員
[cpp] #include <iostream >
using namespace std;
class MyClass_B;
//A 類
class MyClass_A
{
public:
MyClass_A(string name)
{
m_name = name;
}
void Function(MyClass_B &myB);
private:
string m_name;
};
//B 類
class MyClass_B
{
public:
MyClass_B(string name)
{
m_name = name;
}
//友元函數聲明,注意和普通函數的區別
friend void MyClass_A::Function(MyClass_B &myB);
private:
string m_name;
};
//函數定義
void MyClass_A::Function(MyClass_B &myB)
{
cout<<myB.m_name<<endl;
}
//測試代碼
int main(int argc,char* argv[])
{
MyClass_A testA("Class A");
MyClass_B testB("Class B");
testA.Function(testB);
return 0;
}
#include <iostream >
using namespace std;
class MyClass_B;
//A 類
class MyClass_A
{
public:
MyClass_A(string name)
{
m_name = name;
}
void Function(MyClass_B &myB);
private:
string m_name;
};
//B 類
class MyClass_B
{
public:
MyClass_B(string name)
{
m_name = name;
}
//友元函數聲明,注意和普通函數的區別
friend void MyClass_A::Function(MyClass_B &myB);
private:
string m_name;
};
//函數定義
void MyClass_A::Function(MyClass_B &myB)
{
cout<<myB.m_name<<endl;
}
//測試代碼
int main(int argc,char* argv[])
{
MyClass_A testA("Class A");
MyClass_B testB("Class B");
testA.Function(testB);
return 0;
}
我們可以看到,B 類,對 A 類其中的一個函數開放,其結果是這個函數可以訪問 B 類的所有元素。
四. 整個類也可以是另一個類的友元
友類的每個成員函數都可以訪問另一個類的所有成員。
示例代碼如下:
[cpp] #include <iostream >
using namespace std;
//類 A
class MyClass_B;
class MyClass_A
{
public:
MyClass_A(string name)
{
m_name = name;
}
//友元類聲明
friend class MyClass_B;
private:
string m_name;
};
//類 B
class MyClass_B
{
public:
MyClass_B(string name)
{
m_name = name;
}
void Display(MyClass_A &myA);
private:
string m_name;
};
//成員函數
void MyClass_B::Display(MyClass_A &myA)
{
cout<<myA.m_name<<endl; //訪問A的私有成員
MyClass_A test("test");
cout<<test.m_name<<endl; //好像A的所有元素在B裡都存在一樣
}
//測試代碼
int main(int argc,char* argv[])
{
MyClass_A testA("Class A");
MyClass_B testB("Class B");
testB.Display(testA);
return 0;
}
#include <iostream >
using namespace std;
//類 A
class MyClass_B;
class MyClass_A
{
public:
MyClass_A(string name)
{
m_name = name;
}
//友元類聲明
friend class MyClass_B;
private:
string m_name;
};
//類 B
class MyClass_B
{
public:
MyClass_B(string name)
{
m_name = name;
}
void Display(MyClass_A &myA);
private:
string m_name;
};
//成員函數
void MyClass_B::Display(MyClass_A &myA)
{
cout<<myA.m_name<<endl; //訪問A的私有成員
MyClass_A test("test");
cout<<test.m_name<<endl; //好像A的所有元素在B裡都存在一樣
}
//測試代碼
int main(int argc,char* argv[])
{
MyClass_A testA("Class A");
MyClass_B testB("Class B");
testB.Display(testA);
return 0;
}此時B可以訪問A的所有元素,就好像A在B裡面一樣。
五. 總結
簡單的說就是:聲明一個友元函數或者是友元類,就是要把自己完全暴露給對方。
作者 lwbeyond