亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

Effective C++ 2e Item42

2019-09-10 09:07:13
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

條款42: 明智地使用私有繼承

條款35說(shuō)明,C++將公有繼承視為 "是一個(gè)" 的關(guān)系。它是通過(guò)這個(gè)例子來(lái)證實(shí)的:假如某個(gè)類層次結(jié)構(gòu)中,Student類從Person類公有繼承,為了使某個(gè)函數(shù)成功調(diào)用,編譯器可以在必要時(shí)隱式地將Student轉(zhuǎn)換為Person。這個(gè)例子很值得再看一遍,只是現(xiàn)在,公有繼承換成了私有繼承:

class Person { ... };

class Student:/t/t      // 這一次我們
 private Person { ... };/t   // 使用私有繼承

void dance(const Person& p);        // 每個(gè)人會(huì)跳舞

void study(const Student& s);       // 只有學(xué)生才學(xué)習(xí)


Person p;/t/t/t   // p是一個(gè)人
Student s;/t/t/t  // s是一個(gè)學(xué)生

dance(p);/t/t/t   // 正確, p是一個(gè)人

dance(s);/t/t/t   // 錯(cuò)誤!一個(gè)學(xué)生不是一個(gè)人

很顯然,私有繼承的含義不是 "是一個(gè)",那它的含義是什么呢?

"別忙!" 你說(shuō)。"在弄清含義之前,讓我們先看看行為。私有繼承有那些行為特征呢?" 那好吧。關(guān)于私有繼承的第一個(gè)規(guī)則正如你現(xiàn)在所看到的:和公有繼承相反,如果兩個(gè)類之間的繼承關(guān)系為私有,編譯器一般不會(huì)將派生類對(duì)象(如Student)轉(zhuǎn)換成基類對(duì)象(如Person)。這就是上面的代碼中為對(duì)象s調(diào)用dance會(huì)失敗的原因。第二個(gè)規(guī)則是,從私有基類繼承而來(lái)的成員都成為了派生類的私有成員,即使它們?cè)诨愔惺潜Wo(hù)或公有成員。行為特征就這些。

這為我們引出了私有繼承的含義:私有繼承意味著 "用...來(lái)實(shí)現(xiàn)"。如果使類D私有繼承于類B,這樣做是因?yàn)槟阆肜妙怋中已經(jīng)存在的某些代碼,而不是因?yàn)轭愋虰的對(duì)象和類型D的對(duì)象之間有什么概念上的關(guān)系。因而,私有繼承純粹是一種實(shí)現(xiàn)技術(shù)。用條款36引入的術(shù)語(yǔ)來(lái)說(shuō),私有繼承意味著只是繼承實(shí)現(xiàn),接口會(huì)被忽略。如果D私有繼承于B,就是說(shuō)D對(duì)象在實(shí)現(xiàn)中用到了B對(duì)象,僅此而已。私有繼承在軟件 "設(shè)計(jì)" 過(guò)程中毫無(wú)意義,只是在軟件 "實(shí)現(xiàn)" 時(shí)才有用。

私有繼承意味著 "用...來(lái)實(shí)現(xiàn)" 這一事實(shí)會(huì)給程序員帶來(lái)一點(diǎn)混淆,因?yàn)闂l款40指出,"分層" 也具有相同的含義。怎么在二者之間進(jìn)行選擇呢?答案很簡(jiǎn)單:盡可能地使用分層,必須時(shí)才使用私有繼承。什么時(shí)候必須呢?這往往是指有保護(hù)成員和/或虛函數(shù)介入的時(shí)候 ---- 但這個(gè)問(wèn)題過(guò)一會(huì)兒再深入討論。

條款41提供了一種方法來(lái)寫(xiě)一個(gè)Stack 模板,此模板生成的類保存不同類型的對(duì)象。你應(yīng)該熟悉一下那個(gè)條款。模板是C++最有用的組成部分之一,但一旦開(kāi)始經(jīng)常性地使用它,你會(huì)發(fā)現(xiàn),如果實(shí)例化一個(gè)模板一百次,你就可能實(shí)例化了那個(gè)模板的代碼一百次。例如Stack模板,構(gòu)成Stack<int>成員函數(shù)的代碼和構(gòu)成Stack<double>成員函數(shù)的代碼是完全分開(kāi)的。有時(shí)這是不可避免的,但即使模板函數(shù)實(shí)際上可以共享代碼,這種代碼重復(fù)還是可能存在。這種目標(biāo)代碼體積的增加有一個(gè)名字:模板導(dǎo)致的 "代碼膨脹"。這不是件好事。

對(duì)于某些類,可以采用通用指針來(lái)避免它。采用這種方法的類存儲(chǔ)的是指針,而不是對(duì)象,實(shí)現(xiàn)起來(lái)就是:

? 創(chuàng)建一個(gè)類,它存儲(chǔ)的是對(duì)象的void*指針。
? 創(chuàng)建另外一組類,其唯一目的是用來(lái)保證類型安全。這些類都借助第一步中的通用類來(lái)完成實(shí)際工作。

下面的例子使用了條款41中的非模板Stack類,不同的是這里存儲(chǔ)的是通用指針,而不是對(duì)象:

class GenericStack {
public:
 GenericStack();
 ~GenericStack();

 void push(void *object);
 void * pop();

 bool empty() const;

private:
 struct StackNode {
   void *data;/t/t    // 節(jié)點(diǎn)數(shù)據(jù)
   StackNode *next;/t       // 下一節(jié)點(diǎn)

   StackNode(void *newData, StackNode *nextNode)
   : data(newData), next(nextNode) {}
 };

 StackNode *top;/t/t/t  // 棧頂

 GenericStack(const GenericStack& rhs);   // 防止拷貝和
 GenericStack&/t/t/t    // 賦值(參見(jiàn)
   operator=(const GenericStack& rhs);    // 條款27)
};


因?yàn)檫@個(gè)類存儲(chǔ)的是指針而不是對(duì)象,就有可能出現(xiàn)一個(gè)對(duì)象被多個(gè)堆棧指向的情況(即,被壓入到多個(gè)堆棧)。所以極其重要的一點(diǎn)是,pop和類的析構(gòu)函數(shù)銷毀任何StackNode對(duì)象時(shí),都不能刪除data指針 ---- 雖然還是得要?jiǎng)h除StackNode對(duì)象本身。畢竟,StackNode 對(duì)象是在GenericStack類內(nèi)部分配的,所以還是得在類的內(nèi)部釋放。所以,條款41中Stack類的實(shí)現(xiàn)幾乎完全滿足the GenericStack的要求。僅有的改變只是用void*來(lái)替換T。

僅僅有GenericStack這一個(gè)類是沒(méi)有什么用處的,但很多人會(huì)很容易誤用它。例如,對(duì)于一個(gè)用來(lái)保存int的堆棧,一個(gè)用戶會(huì)錯(cuò)誤地將一個(gè)指向Cat對(duì)象的指針壓入到這個(gè)堆棧中,但編譯卻會(huì)通過(guò),因?yàn)閷?duì)void*參數(shù)來(lái)說(shuō),指針就是指針。

為了重新獲得你所習(xí)慣的類型安全,就要為GenericStack創(chuàng)建接口類(interface class),象這樣:

class IntStack {/t/t  // int接口類
public:
 void push(int *intPtr) { s.push(intPtr); }
 int * pop() { return static_cast<int*>(s.pop()); }
 bool empty() const { return s.empty(); }

private:
 GenericStack s;/t/t // 實(shí)現(xiàn)
};

class CatStack {/t/t  // cat接口類
public:
 void push(Cat *catPtr) { s.push(catPtr); }
 Cat * pop() { return static_cast<Cat*>(s.pop()); }
 bool empty() const { return s.empty(); }

private:
 GenericStack s;/t/t // 實(shí)現(xiàn)
};

正如所看到的,IntStack和CatStack只是適用于特定類型。只有int指針可以被壓入或彈出IntStack,只有Cat指針可以被壓入或彈出CatStack。IntStack和CatStack都通過(guò)GenericStack類來(lái)實(shí)現(xiàn),這種關(guān)系是通過(guò)分層(參見(jiàn)條款40)來(lái)體現(xiàn)的,IntStack和CatStack將共享GenericStack中真正實(shí)現(xiàn)它們行為的函數(shù)代碼。另外,IntStack和CatStack所有成員函數(shù)是(隱式)內(nèi)聯(lián)函數(shù),這意味著使用這些接口類所帶來(lái)的開(kāi)銷幾乎是零。

但如果有些用戶沒(méi)認(rèn)識(shí)到這一點(diǎn)怎么辦?如果他們錯(cuò)誤地認(rèn)為使用GenericStack更高效,或者,如果他們魯莽而輕率地認(rèn)為類型安全不重要,那該怎么辦?怎么才能阻止他們繞過(guò)IntStack和CatStack而直接使用GenericStack(這會(huì)讓他們很容易地犯類型錯(cuò)誤,而這正是設(shè)計(jì)C++所要特別避免的)呢?

沒(méi)辦法!沒(méi)辦法防止。但,也許應(yīng)該有什么辦法。

在本條款的開(kāi)始我就提到,要表示類之間 "用...來(lái)實(shí)現(xiàn)" 的關(guān)系,有一個(gè)選擇是通過(guò)私有繼承?,F(xiàn)在這種情況下,這一技術(shù)就比分層更有優(yōu)勢(shì),因?yàn)橥ㄟ^(guò)它可以讓你告訴別人:GenericStack使用起來(lái)不安全,它只能用來(lái)實(shí)現(xiàn)其它的類。具體做法是將GenericStack的成員函數(shù)聲明為保護(hù)類型:

class GenericStack {
protected:
 GenericStack();
 ~GenericStack();

 void push(void *object);
 void * pop();

 bool empty() const;

private:
 .../t/t/t     // 同上
};

GenericStack s;/t/t   // 錯(cuò)誤! 構(gòu)造函數(shù)被保護(hù)


class IntStack: private GenericStack {
public:
 void push(int *intPtr) { GenericStack::push(intPtr); }
 int * pop() { return static_cast<int*>(GenericStack::pop()); }
 bool empty() const { return GenericStack::empty(); }
};

class CatStack: private GenericStack {
public:
 void push(Cat *catPtr) { GenericStack::push(catPtr); }
 Cat * pop() { return static_cast<Cat*>(GenericStack::pop()); }
 bool empty() const { return GenericStack::empty(); }
};

IntStack is;/t/t     // 正確

CatStack cs;/t/t     // 也正確

和分層的方法一樣,基于私有繼承的實(shí)現(xiàn)避免了代碼重復(fù),因?yàn)檫@個(gè)類型安全的接口類只包含有對(duì)GenericStack函數(shù)的內(nèi)聯(lián)調(diào)用。

在GenericStack類之上構(gòu)筑類型安全的接口是個(gè)很花俏的技巧,但需要手工去寫(xiě)所有那些接口類是件很煩的事。幸運(yùn)的是,你不必這樣。你可以讓模板來(lái)自動(dòng)生成它們。下面是一個(gè)模板,它通過(guò)私有繼承來(lái)生成類型安全的堆棧接口:

template<class T>
class Stack: private GenericStack {
public:
 void push(T *objectPtr) { GenericStack::push(objectPtr); }
 T * pop() { return static_cast<T*>(GenericStack::pop()); }
 bool empty() const { return GenericStack::empty(); }
};

這是一段令人驚嘆的代碼,雖然你可能一時(shí)還沒(méi)意識(shí)到。因?yàn)檫@是一個(gè)模板,編譯器將根據(jù)你的需要自動(dòng)生成所有的接口類。因?yàn)檫@些類是類型安全的,用戶類型錯(cuò)誤在編譯期間就能發(fā)現(xiàn)。因?yàn)镚enericStack的成員函數(shù)是保護(hù)類型,并且接口類把GenericStack作為私有基類來(lái)使用,用戶將不可能繞過(guò)接口類。因?yàn)槊總€(gè)接口類成員函數(shù)被(隱式)聲明為inline,使用這些類型安全的類時(shí)不會(huì)帶來(lái)運(yùn)行開(kāi)銷;生成的代碼就象用戶直接使用GenericStack來(lái)編寫(xiě)的一樣(假設(shè)編譯器滿足了inline請(qǐng)求 ---- 參見(jiàn)條款33)。因?yàn)镚enericStack使用了void*指針,操作堆棧的代碼就只需要一份,而不管程序中使用了多少不同類型的堆棧。簡(jiǎn)而言之,這個(gè)設(shè)計(jì)使代碼達(dá)到了最高的效率和最高的類型安全。很難做得比這更好。

本書(shū)的基本認(rèn)識(shí)之一是,C++的各種特性是以非凡的方式相互作用的。這個(gè)例子,我希望你能同意,確實(shí)是非凡的。

從這個(gè)例子中可以發(fā)現(xiàn),如果使用分層,就達(dá)不到這樣的效果。只有繼承才能訪問(wèn)保護(hù)成員,只有繼承才使得虛函數(shù)可以重新被定義。(虛函數(shù)的存在會(huì)引發(fā)私有繼承的使用,例子參見(jiàn)條款43)因?yàn)榇嬖谔摵瘮?shù)和保護(hù)成員,有時(shí)私有繼承是表達(dá)類之間 "用...來(lái)實(shí)現(xiàn)" 關(guān)系的唯一有效途徑。所以,當(dāng)私有繼承是你可以使用的最合適的實(shí)現(xiàn)方法時(shí),就要大膽地使用它。同時(shí),廣泛意義上來(lái)說(shuō),分層是應(yīng)該優(yōu)先采用的技術(shù),所以只要有可能,就要盡量使用它。

上一篇:確認(rèn)Buffer

下一篇:Foo 的辭源

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表

圖片精選

www.一区二区三区.com| 99国产牛牛视频在线网站| 亚洲三级毛片| 中文字幕在线不卡视频| 久久精品午夜福利| 99国产欧美另类久久久精品| 欧美日韩黄色一区二区| 成功精品影院| 欧美噜噜久久久xxx| 一区二区三区精品视频在线观看| 亚洲精品日韩精品| 亚洲天堂岛国片| 2020色愉拍亚洲偷自拍| aaa国产精品| 亚洲一区国产精品| 色婷婷亚洲十月十月色天| 久久成人18免费网站| 欧洲精品一区二区三区久久| 精品免费一区二区三区| 久久成人久久鬼色| 免费观看在线综合| 在线看片国产福利你懂的| 在线看a视频| 成人一区二区三区仙踪林| 懂色av一区二区三区| 成人福利在线| 五月激情五月婷婷| 亚洲综合视频在线观看| 国产ktv在线视频| 91porny在线| 成人黄网18免费观看的网站| 精品一区二区国产| 免费看久久久| 秋霞网一区二区| 成人a级免费视频| 波多野结衣影片| 综合久久给合久久狠狠狠97色| 亚洲精品一区二区三区99| 日韩漫画puputoon| 婷婷五月综合激情| 麻豆视频一区二区| 国产美女高潮一区二区三区| 另类春色校园亚洲| аⅴ天堂中文在线网| 北条麻妃一区二区三区| 免费观看黄一级视频| 2020日本在线视频中文字幕| 色琪琪一区二区三区亚洲区| 国产精品国产亚洲精品看不卡15| 国产一区日韩欧美| 国产精品三级网站| 日本久久久精品视频| www.51av欧美视频| 自拍偷拍欧美日韩| 韩国成人福利片在线播放| 国产精品456露脸| 色综合久久中文综合久久97| 中文字幕在线永久在线视频2020| 神马午夜电影一区二区三区在线观看| 99热99re6国产在线播放| 奇米影视第四色777| 欧美日韩免费观看一区三区| 91热福利电影| 亚洲欧美日韩国产一区二区三区| 亚洲精品中文字幕无码蜜桃| 91麻豆桃色免费看| 午夜av区久久| 国产精品一区二区亚洲| 国产卡一卡2卡三卡免费视频| 麻豆av免费在线| 日韩免费一区二区三区在线播放| 久久网站免费观看| 亚洲美女屁股眼交3| 国产午夜免费视频| 高清在线观看免费| 亚洲v日本v欧美v久久精品| 国内精品在线一区| 日韩欧美国产系列| 亚洲精品一二三区| 中文在线观看免费| 国产成人无码a区在线观看视频| 日韩一区二区麻豆国产| 日韩亚洲欧美中文在线| 91成人免费| 亚洲成人av一区| 在线观看成人毛片| 97在线精品视频| 美女扒开腿免费视频| 桃乃木香奈和黑人aⅴ在线播放| 男男做性免费视频网| 国产亚洲成av人片在线观黄桃| 亚洲人午夜精品免费| 电影在线观看一区二区| 欧美久久综合| 三级视频在线播放| 91传媒免费视频| 亚洲国产精品欧美久久| 亚洲小说区图片| 国产亚洲色婷婷久久99精品| 成人午夜一级| 欧美剧情电影在线观看完整版免费励志电影| freexxx性亚洲精品| 中文在线а√在线8| 亚洲免费观看在线视频| 夜夜操 天天操| 制服丝袜亚洲色图| 日韩在线www| 亚洲天堂成人在线| 久久综合成人网| 久久精品a一级国产免视看成人| 日本在线看片免费人成视1000| 免费观看一级一片| 九一免费在线观看| 欧美精品日韩综合在线| 国产a久久麻豆| 综合日韩av| 美日韩精品视频| 日本一级二级视频| 久久国产主播| 国产精品一区二区三区www| 女教师淫辱の教室蜜臀av软件| 91高清在线免费观看| 青娱乐在线视频免费观看| 在线国产一区二区三区| 欧美性老头oldtight| 欧美福利视频在线| 国产精品9区| av第一福利大全导航| 97国产在线| 狠狠躁日日躁夜夜躁av| 欧美亚洲韩国| 天天干天天操天天爱| 任你弄精品视频免费观看| 亚洲一区二区三区在线看| 欧美性受xxxx黒人xyx性爽| 高清成人在线| 找av导航入口| 精品人妻一区二区三区蜜桃视频| 天天射综合网视频| 无码少妇一区二区| 亚洲欧美一区二区三区孕妇| 欧美精品七区| 欧美激情在线一区二区三区| 手机av免费观看| 全国男人的天堂网| 精品这里只有精品| 美女福利视频在线| 国产农村妇女毛片精品久久| 久久精品成人欧美大片| 三上悠亚在线观看视频| 国产精品国产三级国产专区53| 97国产精品视频| 日韩欧美一区二区三区四区五区| 国产高清一级毛片在线不卡| 无码人妻精品一区二区三区蜜桃91| 国产精品一区二区黑丝| 一个色的综合| 在线播放性xxx欧美| 日韩一区二区三区视频| 国产在线播放精品| 午夜久久久久久久久久久| 亚洲美女av黄| 少妇特黄a一区二区三区| 国产精品视频99| 手机免费看av片| 午夜日韩福利| 91九色最新地址| 日本综合在线观看| 欧美亚洲天堂网| 久久亚洲国产精品尤物| 亚洲欧美色综合| 日韩欧美视频专区| 国产精品免费看久久久无码| 国产一区二区三区中文| 欧美人与动牲性行为| 国产一区二区三区av电影| 99久久人爽人人添人人澡| 最近2018年手机中文在线| 亚洲伦理在线观看| 一区二区三区国产好的精华液| 国产午夜精品久久| 男女激情网站| 精灵使的剑舞无删减版在线观看| 中文字幕精品—区二区| 日韩福利一区二区| 国产精品午夜在线观看| 久久成人麻豆午夜电影| 在线看中文字幕| 国产精品久久毛片av大全日韩| 亚洲国产欧美另类| 欧美日韩中文视频| 国产女人精品视频| 欧美一区二区在线视频| 国产精品天美传媒| 成年网站免费视频黄| 欧美一区亚洲二区| 国产精品国产三级国产aⅴ| 日韩中文av在线| 91九色蝌蚪在线| 国产在线精品一区二区不卡| 天堂а√在线中文在线鲁大师| 久久人人97超碰国产公开结果| 久久精品视频日本| 国产精品久久久久久久免费软件| 午夜在线视频免费| 性做久久久久久免费观看欧美| 成人免费视频| 蜜臀av一区二区| 国产精品乱码人人做人人爱| 欧美一区二区三区性视频| 国产精品熟女视频| www.av免费| 亚洲天堂av高清| 黄色在线免费观看网站| 国内精品**久久毛片app| 亚洲久久在线观看| 久久亚洲国产精品尤物| 亚洲乱码电影| 综合国产在线| www.热久久| 国产不卡视频一区| av免费观看大全| 久久夜色精品国产噜噜av| 日韩久久久久久久| 欧美性大战久久久久久久蜜臀| 亚洲大奶少妇| 中文在线免费看视频| 69av一区二区三区| 中文字幕国产高清| 色94色欧美sute亚洲线路二| 欧美三区在线| 国产精品一区二区免费视频| 精品亚洲第一| 秘密影院久久综合亚洲综合| 黄色日韩网站| 91精品久久久久久久久久不卡| 国产精品女上位| 亚洲欧洲久久久| 亚洲成人av免费在线观看| 男女啪啪无遮挡网站| 97色在线观看免费视频| 免费网站看电影大片| 中文字幕视频在线| 九热视频在线观看| 僵尸再翻生在线观看免费国语| 亚洲成av人片乱码色午夜| www狠狠操| 欧美精品情趣视频| 美女一区网站| 精品黑人一区二区三区观看时间| 国产又粗又长又大的视频| 樱桃视频在线观看一区| 免费久久99精品国产自| 欧美激情性做爰免费视频| 国产精品一区视频网站| 亚洲精品乱码久久久久久久久久久久| 伦av综合一区| 欧美夫妻性视频| 亚洲欧美一区二区原创| 影音先锋欧美资源| 亚色视频在线观看| 欧美精品a∨在线观看不卡| 日韩午夜中文字幕| 久久久久久久久99| 亚洲欧洲激情在线乱码蜜桃| 好想男人揉我下面好多水| 国产99视频精品免视看7| 99久久伊人精品影院| 91国产视频在线播放| 久久一区二区三区视频| 91麻豆精品成人一区二区| 欧美做受高潮中文字幕| 国产女教师bbwbbwbbw| 亚洲精品国产suv一区88| 欧美视频免费一区二区三区| 日本一级免费视频| 亚洲视频自拍| 色综合久久久久综合一本到桃花网| 99久久国产综合色|国产精品| 丝袜美腿亚洲一区| 韩国三级视频在线观看| 日韩精品国产精品| 一区二区三区免费在线视频| 久久久久久av无码免费网站| 男人操女人免费软件| 秋霞av国产精品一区| 男男电影完整版在线观看| 精品国产伦一区二区三区免费| 波多野结衣一区二区三区四区| 97免费在线观看视频| av电影在线免费观看| 69久久99精品久久久久婷婷| 国产精品玖玖玖| 国产bdsm| 蜜桃狠狠狠狠狠狠狠狠狠| 韩国三级在线观看久| 欧美日韩国产美女| 亚洲第一大网站| 中文字幕精品在线观看| 欧美另类高清videos| 久久影视一区| 99久久精品无码一区二区毛片| 最新中文字幕一区| 日韩av手机在线免费观看| 在线观看国产精品91| 成人开心激情| 97**国产露脸精品国产| 亚洲国产精品一区制服丝袜| 亚洲高清资源综合久久精品| 亚洲香蕉伊综合在人在线视看| 欧美国产综合| 老熟女高潮一区二区三区| 午夜大片在线观看| 青青草一区二区| 中文字幕乱视频| 国产精品秘入口18禁麻豆免会员| www..69.hd| 久久久久久久电影一区| 91视频最新入口| 加勒比视频一区| 欧美激情视频免费看| 九七影院97影院理论片免费| 国产成人艳妇aa视频在线| 人禽交欧美网站免费| 窝窝社区一区二区| 91美女精品福利| 麻豆影视国产在线观看| 久久久www免费人成黑人精品|