C++中友元的實例詳解
C++中友元的實例詳解
盡管友元被授予從外部訪問類的私有部分的權(quán)限,但他們并不與面向?qū)ο蟮木幊趟枷胂嚆#幌喾此岣吡斯步涌诘撵`活性。
一、友元類
友元聲明可以位于公有、私有活保護部分、其所在位置無關(guān)緊要
我直接貼出一個摘自< c++ primer plus >的例子來演示 c++ 友元類
其中 Remote 為 Tv的友元類。
Tv.h
#ifndef TV_H_ #define TV_H_ /*一個類 電視 */ class Tv { public: friend class Remote; //Remote類可以訪問Tv Privite 的私有部分 enum { off,on //開關(guān) }; enum { MinVal,MaxVal=20 //音量 }; enum { Antena,Cable //使用的天線、還是電纜 }; enum { TV ,DVD //工作模式 }; Tv(int s = off, int mc = 125) :state(s), volume(5), maxchannel(mc), channel(5), mode(Cable), input(TV) {} void onoff() { state = (state == on) ? off : on; } bool ison()const { return state == on; } bool volup(); //增大聲音 bool voldown(); //減小聲音 void chanup(); //頻道 + void chandown();//頻道 - void set_mode() { mode = (mode == Antena) ? Cable : Antena; } void set_input() { input = (input == TV) ? DVD : TV; } void settings()const; //顯示所有設(shè)置 private: int state; // 開或者 關(guān) int volume; // 音量 int maxchannel; //最大 int channel; //當(dāng)前頻道 int mode; // 廣播還是 電纜 int input; //Tv 或者 DVD }; /*Remote 的定義 (遙控器) */ class Remote { private : int mode; // 控制 TV 或 DVD public: Remote(int m = Tv::TV) :mode(m) {} bool volup(Tv & t) { return t.volup(); } bool voldown(Tv & t) { return t.voldown(); } void onoff(Tv & t) { return t.onoff(); } void chanup(Tv & t) { return t.chanup(); } void chandown(Tv & t) { return t.chandown(); } void set_chan(Tv &t, int c) { t.channel = c; } //訪問了Tv的私有成員 void set_mode(Tv &t) { t.set_mode(); } void set_input(Tv &t) { t.set_input(); } }; #endif // TV_H_
Tv.cpp
#include "stdafx.h" #include "Tv.h" #include <iostream> bool Tv::volup() { if (volume < MaxVal) { volume++; return true; } else { return false; } } bool Tv::voldown() { if (volume > MinVal) { volume--; return true; } else { return false; } } void Tv::chanup() { if (channel < maxchannel) channel++; else channel = 1; } void Tv::chandown() { if (channel > 1) channel--; else channel = maxchannel; } void Tv::settings() const { using std::cout; using std::endl; cout << "TV is " << (state == off ? "off" : "on") << endl; if (state == on) { cout << "Volume setting =" << volume << endl; cout << "Channel setting = " << channel << endl; cout << "Mode = " << (mode == Antena ? "antenna" : "cable") << endl; cout << "Input = " << (input == TV ? "TV" : "DVD") << endl; } }
測試代碼:
#include "stdafx.h" #include "tv.h" #include <iostream> int main() { using std::cout; Tv s42; cout << "Initial settings for 42 \" Tv: \n"; s42.settings(); s42.onoff(); s42.chanup(); cout << " \n Adjusted settings for 42 \" Tv: \n"; s42.chanup(); cout << "\n Adjusted settings for 42 \" Tv: \n"; s42.settings(); Remote grey; grey.set_chan(s42, 10); grey.volup(s42); grey.volup(s42); cout << " \n s42 \" settings after using remote: \n"; s42.settings(); Tv s58(Tv::on); s58.set_mode(); grey.set_chan(s58, 58); cout << " \n s58 \" setting: \n"; s58.settings(); system("pause"); return 0; }
運行結(jié)果:
Initial settings for 42 " Tv: TV is off Adjusted settings for 42 " Tv: Adjusted settings for 42 " Tv: TV is on Volume setting =5 Channel setting = 7 Mode = cable Input = TV s42 " settings after using remote: TV is on Volume setting =7 Channel setting = 10 Mode = cable Input = TV s58 " setting: TV is on Volume setting =5 Channel setting = 58 Mode = antenna Input = TV 請按任意鍵繼續(xù). . .
上述代碼中將Remote類設(shè)置成為了Tv類的友元類,但事實上我們看到:唯一訪問Tv的成員的方法是void set_chan(Tv &t, int c) { t.channel = c; } ,因此它是唯一需要友元的方法。因此不必讓整個類成為友元,這就引出了我們下面要講的的友元成員函數(shù)。
二、友元成員函數(shù)
我們要再Tv中將Remote::set_chan()設(shè)置成友元:
clas Tv { friend void Remote::set_chan(Tv & t,int c ) ; }
然而要使編譯器能夠處理這條語句,它必須知道Remote的定義。否則,它無法知道Remote是一個類。而 set_chan是這個類的方法。這意味著應(yīng)將Remote的定義放到Tv的定義前面。Remote的方法提到了Tv對象,而意味著Tv定義應(yīng)當(dāng)位于Remote定義之前,避開這種循環(huán)依賴的方法是,使用前向聲明。
所以應(yīng)該這樣:
class Tv ; //前向聲明 class Remote{...} class Tv {...}
這里還有一個麻煩就是:
Remote 包含了內(nèi)聯(lián)代碼例如:void onoff(Tv &t) {t.onoff();};
由于這將調(diào)用Tv的一個方法,所以編譯器此時已經(jīng)看到了Tv類的聲明,這樣才能知道Tv有哪些方法,但正如看到的,該聲明位于Remote聲明的后面。這種問題的解決方法是:使用Remote聲明中只包含方法聲明,并將實際的定義放到Tv類之后。 所以最終應(yīng)該這樣:
class Tv; //前向聲明 class Remote {...} //如要用到Tv 只能是方法聲明 class Tv{...} //接著寫Remote的定義
這里通過方法定義中使用 inline關(guān)鍵字,仍然可以使方法稱為內(nèi)聯(lián)方法
所以程序最終將tv.h改為:
#ifndef TV_H_ #define TV_H_ class Tv; //前向聲明 class Remote { public: enum { off, on //開關(guān) }; enum { MinVal, MaxVal = 20 //音量 }; enum { Antena, Cable //使用的天線、還是電纜 }; enum { TV, DVD //工作模式 }; private: int mode; // 控制 TV 或 DVD public: Remote(int m = TV) :mode(m) {} //用到了Tv 只能是聲明 bool volup(Tv & t); bool voldown(Tv & t); void onoff(Tv & t); void chanup(Tv & t); void chandown(Tv & t); void set_chan(Tv &t, int c); void set_mode(Tv &t); void set_input(Tv &t); }; class Tv { public: friend void Remote::set_chan(Tv & t,int c); //友元成員函數(shù) enum { off, on //開關(guān) }; enum { MinVal, MaxVal = 20 //音量 }; enum { Antena, Cable //使用的天線、還是電纜 }; enum { TV, DVD //工作模式 }; Tv(int s = off, int mc = 125) :state(s), volume(5), maxchannel(mc), channel(5), mode(Cable), input(TV) {} void onoff() { state = (state == on) ? off : on; } bool ison()const { return state == on; } bool volup(); //增大聲音 bool voldown(); //減小聲音 void chanup(); //頻道 + void chandown();//頻道 - void set_mode() { mode = (mode == Antena) ? Cable : Antena; } void set_input() { input = (input == TV) ? DVD : TV; } void settings()const; //顯示所有設(shè)置 private: int state; // 開或者 關(guān) int volume; // 音量 int maxchannel; //最大 int channel; //當(dāng)前頻道 int mode; // 廣播還是 電纜 int input; //Tv 或者 DVD }; inline bool Remote::volup(Tv & t) { return t.volup(); } inline bool Remote::voldown(Tv & t) { return t.voldown(); } inline void Remote::onoff(Tv & t) { return t.onoff(); } inline void Remote::chanup(Tv & t) { return t.chanup(); } inline void Remote::chandown(Tv & t) { return t.chandown(); } inline void Remote::set_chan(Tv &t, int c) { t.channel = c; } inline void Remote::set_mode(Tv &t) { return t.set_mode(); } inline void Remote::set_input(Tv &t) { return t.set_input(); } #endif // TV_H_
測試結(jié)果不變。
*另外:也可一個將內(nèi)聯(lián)函數(shù)放在tv.cpp中,但必須去掉inline關(guān)鍵字,這樣函數(shù)的連接性將成為外部的。
三、其他友元關(guān)系
1、上面的代碼表示的是Remote是Tv的友元。但我們有時也會用到2個類互相友元。即Remote是Tv的友元,同時 Tv又是Remote的友元
他們定義與下面類似:
class Remote class Tv { friend clas Remote public: void buzz(Remote & r) ; ... } class Remote { friend class Tv; public: void Bool volup(Tv & t){t.volup();} ... } inline void Tv::buzz(Remote & r) { ... }
由于Remote的聲明位于Tv聲明的后面,所以可以在類的定義Remote::volup(),但Tv::buzz()方法必須在Tv聲明的外部定義,使其位于Remote聲明的外面。如果不希望buzz()是內(nèi)聯(lián)的,則應(yīng)在一個單獨的方法定義文件中定義它。
2、共同的友元。
需要使用友元的另一種情況是,函數(shù)需要訪問兩個類的私有數(shù)據(jù)。它可以是一個類的友元,同時是另一個類的友元。示例如下:
class Analyzer; class Probe { friend void sync (Analyzer & a,const Probe & p) ; friend void sync (Probe & p,const Analyzer & a); ... }; class Analyzer { friend void sync (Analyzer & a,const Probe & p) ; friend void sync (Probe & p,const Analyzer & a); } inline void sync (Analyzer & a,const Probe & p) { ... } inline void sync (Probe & p,const Analyzer & a) { ... }
如有疑問請留言或者到本站社區(qū)交流討論,感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
相關(guān)文章
C++編程產(chǎn)生指定范圍內(nèi)的隨機數(shù)
這篇文章主要為大家詳細介紹了C++編程產(chǎn)生指定范圍內(nèi)的隨機數(shù),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-09-09C++結(jié)構(gòu)體數(shù)組實現(xiàn)貪吃蛇
這篇文章主要為大家詳細介紹了C++結(jié)構(gòu)體數(shù)組實現(xiàn)貪吃蛇,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-03-03Qt5.9.5 隨機轉(zhuǎn)盤小項目的實現(xiàn)示例
本文主要介紹了Qt5.9.5隨機轉(zhuǎn)盤小項目的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06C語言統(tǒng)計一篇英文短文中單詞的個數(shù)實例代碼
本文通過實例代碼給大家介紹的C語言統(tǒng)計一篇英文短文中單詞的個數(shù),代碼簡單易懂,非常不錯,具有參考借鑒價值,需要的朋友參考下吧2018-03-03C語言數(shù)據(jù)結(jié)構(gòu)之圖書借閱系統(tǒng)
這篇文章主要為大家詳細介紹了C語言數(shù)據(jù)結(jié)構(gòu)之圖書借閱系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-03-03