友元
友元 英文 friend。friend 翻譯成中文就是朋友,翻譯成術語就是:友元。朋友就很好了解了,我的錢你随便花,我的東西你随便用;當然我也是你的朋友,你的錢我随便花,你的東西我随便用。
當然在 C++ 裡,類與類 之間可以作為友元,那麼這個類就可以去操作另外一個類裡面私有的成員;函數與函數 之間也可以作為 友元,是以友元分為: 友元函數 和 友元類。
我們通過一個例子一看就明白了:
寫代碼
#include <iostream>
#include <string>
using namespace std;
class Screen{
public:
typedef std::string::size_type index;
Screen(int ht=, int wd=):contents(ht*wd, ' '), cursor(), height(ht), width(wd){}
int area() const{
return height * width;
}
private:
std::string contents;
index cursor;
int height, width;
};
int main(){
Screen a;
cout << a.area() << endl;
cout << "OK" << endl;
return ;
}
運作現在的程式,程式是可以正常使用的。
現在,我們在
main()
函數的同一級,編寫一個函數,這個函數的功能是:計算螢幕(Screen)的面積。
// 這個函數不是類的成員函數
int calcArea(Screen & screen){
return screen.height * screen.width;
}
如果這個函數像上面這個樣子編寫,程式編譯都通不過。因為
height
和
width
都是
Screen
類的私有成員。這兩個私有的資料成員隻能在類的内部使用,隻能被類的内部函數使用,因為這個
calcArea()
函數不是類内部的成員函數,是以它是不能使用類内部的私有成員的。
那麼,假如現在,我們把這個
calcArea()
函數變成這個
Screen
類的友元,就是朋友,那麼這個函數就可以使用類裡面私有的成員了。就像是:你是我的朋友,到我家裡來,就像到自己家裡一樣,随便吃随便用随便拿。
現在我們就來定義友元函數。我們将
calcArea()
函數定義成友元函數。
在
Screen
類裡面,
public
裡面添加下面這句代碼就可以。就這麼簡單:
friend int calcArea(Screen & screen);
現在,我們在編譯程式,就沒有錯誤了。運作也沒有問題。
main()
函數裡面寫成下面這個樣子,來測試:
int main(){
Screen a;
cout << a.area() << endl;
cout << calcArea(a) << endl;
cout << "OK" << endl;
while(){}
return ;
}
我們也可以将一個類編寫成友元,我們現在來看下面這個例子:(注意: 要将下面的這段代碼放到
Screen
類的下面,否則
Window_Mgr
類找不到
Screen
類。)
// 視窗管理類 - 對Screen類進行管理
class Window_Mgr{
public:
// 重定位 - 就是改變視窗的height 和 width
void relocate(int r, int c, Screen& s){
s.height += r;
s.width + c;
}
};
因為
Screen
類裡的
height
和
width
是私有的,不能再
Window_Mgr
類裡面使用的,除非它是友元。
現在編譯程式是報錯的。
我們現在可以将
Window_Mgr
類作為
Screen
類的友元。需要做的事情,隻需要:在
Screen
類裡面的
public
裡面添加下面一句代碼:
friend class Window_Mgr;
現在,我們将
Window_Mgr
這個整個類都作為
Screen
類的友元,也就是說:它們現在是朋友,我們家裡的人可以随便到你們家裡面來,你們家裡的人也可以随便到我們家裡面來。
我們在
main()
函數裡面測試一下:
int main(){
Screen a(, );
cout << a.area() << endl;
Window_Mgr w;
w.relocate(, , a);
cout << calcArea(a) << endl;
cout << "OK" << endl;
while(){}
return ;
}
這就是友元,懂了嗎?
如果我們現在不行讓這個
Window_Mgr
類作為
Screen
類的友元,而是希望隻是
Window_Mgr
類中的一個成員函數是
Screen
類的友元。要如何操作呢?
我們在定義一個類,
Dog
。
Dog
類裡面就有很多的成員函數。
我現在不想将
Dog
類全部做成
Screen
類的友元,我隻想将
Dog
類裡面的
foo()
共有函數作為
Screen
類的友元,那現在我們要如何去做呢?
很簡單,我們在
Screen
類的
public
裡面添加下面這句代碼就可以:
friend int Dog::foo(Screen & );
Q: 現在程式編譯時會通過的,這是為什麼?
A: 有一個問題需要強調一下:友元定義 和 友元聲明 之間有一個依賴。
如果我們将
Dog
類 放在
Screen
類的下面,那麼
Dog
類是可以找到
Screen
類,但是
Screen
類卻找不到
Dog
類裡面的
foo()
函數,因為我們在編寫
foo()
函數的時候,是使用的聲明和定義一體的形式編寫的。
如果我們将
Dog
類 放在
Screen
類的上面, 那麼
Screen
類是可以找到
Dog
類裡面的
foo()
函數,但是
Dog
類現在又找不到
Screen
類了。是以,不管你将
Dog
類放在程式的什麼位置,程式都是沒有辦法編譯通過。要怎樣解決這個問題呢?
我們需要在
Screen
類上面 這樣寫:
class Screen;
class Dog{
public:
int foo(Screen & screen);
int koo(Screen & screen){
return ;
}
};
先對
Screen
類進行聲明,接下定義
Dog
類。并且在
Dog
類裡面 我們将
foo()
函數寫成聲明的形式。這樣就沒有使用到
Screen
類裡面的成員,這樣,程式在編譯這段代碼的時候不需要去找
Screen
的定義。
接着,我們在
Screen
類的下面 這樣寫:
int Dog::foo(Screen & screen){
return screen.height * screen.width;
}
我們在
Screen
類的下面都
Dog
類裡面的成員函數
foo()
函數進行定義。這樣做的原因是:因為
foo()
成員函數裡面使用到了
Screen
類裡面定義的成員變量,程式在編譯這段函數的代碼的時候,會去上向上找
Screen
類的定義,剛好我們将
foo()
函數的定義寫在
Screen
定義的下面,是以這樣寫就可以用個編譯。
現在在
main()
函數中寫一些測試代碼:
int main(){
Screen a(, );
cout << a.area() << endl;
Dog d;
cout << d.foo(a) << endl;
cout << "OK" << endl;
while(){}
return ;
}
現在 友元 我們就都介紹完畢了。
最後,完整的代碼貼上:
#include <iostream>
#include <string>
using namespace std;
class Screen;
class Dog{
public:
int foo(Screen & screen);
int koo(Screen & screen){
return ;
}
};
class Screen{
public:
friend int calcArea(Screen & screen);
friend class Window_Mgr;
friend int Dog::foo(Screen & screen);
typedef std::string::size_type index;
Screen(int ht=, int wd=):contents(ht*wd, ' '),
cursor(), height(ht), width(wd){}
int area() const{
return height * width;
}
private:
std::string contents;
index cursor;
int height, width;
};
// 視窗管理類 - 對Screen類進行管理
class Window_Mgr{
public:
// 重定位 - 就是改變視窗的height 和 width
void relocate(int r, int c, Screen& s){
s.height += r;
s.width += c;
}
};
int Dog::foo(Screen & screen){
return screen.height * screen.width;
}
// 這個函數不是類的成員函數
int calcArea(Screen & screen){
return screen.height * screen.width;
}
int main(){
Screen a(, );
cout << a.area() << endl;
Window_Mgr w;
w.relocate(, , a);
cout << calcArea(a) << endl;
Dog d;
cout << d.foo(a) << endl;
cout << "OK" << endl;
while(){}
return ;
}
總結:
1 . 今天我們學習的就是友元,友元就是找朋友。我們可以将一個函數作為友元,我們也可以将一個類作為友元,也可以将類中的一個成員函數作為友元。
2 . 所有友元函數有兩種: 普通函數 和 類的成員函數(共有 和 私有都可以。)
3 . 友元,道理上是很簡單的。友元了之後,就可以操作所有私有的資料成員和私有函數。