青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆-19  評(píng)論-2  文章-0  trackbacks-0

========================
Effective C++   設(shè)計(jì)與聲明
書(shū)作者:Scott Meyers
原筆記作者:Justin
========================

Item 18 : 接口應(yīng)該容易被正確使用,不易被誤用
--------------------------------------------------
 tag:消除客戶(hù)的資源管理責(zé)任  tr1::shared_ptr  cross-DLL problem
 
 用戶(hù)使用接口時(shí)卻沒(méi)有獲得預(yù)期的行為,這個(gè)代碼不應(yīng)該通過(guò)編譯。
 
 用錯(cuò)的可能有:
 ·調(diào)用接口時(shí)輸入了錯(cuò)誤的參數(shù)。
  如(一個(gè)接受年、月、日為參數(shù)的接口函數(shù),用戶(hù)可以輕易給出各種錯(cuò)誤的輸入),
  解決辦法:用對(duì)象來(lái)約束參數(shù)輸入的范圍(不接受簡(jiǎn)單的整數(shù)作為輸入,而是Date、Mon、Year對(duì)象)
   struct Day{ explicit Day(int d):val(d){}  int val;}  
   class Month{
    public:
     static Month May(){ return Month(5); }
    private:
     explicit Month(int m);
   }      
   Date d(Month::Mar(),Day(20),Year(1995));
  
 ·用常規(guī)的用法調(diào)用“特別”設(shè)計(jì)的接口。所以需要盡可能的把自己的設(shè)計(jì)往常規(guī)上靠:數(shù)據(jù)對(duì)象的行為要盡可能符合內(nèi)建對(duì)象(比如int)的行為;接口的名字和意義要盡可能一致(比如STL中的容器基本都有一個(gè)叫做size的返回容器大小的接口)……這樣做鼓勵(lì)用戶(hù)去正確的看待和使用你的接口。
 
 ·忘了處理調(diào)用接口后的遺留問(wèn)題。因此不要讓用戶(hù)去“記得”做一些事情。
  如設(shè)計(jì)一個(gè)接口返回一個(gè)指向某新建對(duì)象的指針,該接口的用戶(hù)需要“記得”去釋放這個(gè)指針?biāo)傅膶?duì)象:如果用戶(hù)忘了釋放或釋放了好幾次,后果就是@#¥%
  解決的辦法之一是讓該接口返回一個(gè)智能指針(嗯……印象模糊了?去看Item14),這樣用戶(hù)用完了就可以“忘記”這個(gè)指針:它自己會(huì)處理后事。
  
 ·所謂的“跨DLL問(wèn)題”(cross DLL problem):在一個(gè)DLL中new一個(gè)對(duì)象,然后對(duì)象被傳到另外一個(gè)DLL里被delete。大師推薦用shared_ptr因?yàn)樗鉀Q了這個(gè)問(wèn)題。
  代價(jià):額外對(duì)象的創(chuàng)建和銷(xiāo)毀需要時(shí)間空間。比如boost的shared_ptr就是普通指針的兩倍大小,還有額外的對(duì)象操作時(shí)間+過(guò)程動(dòng)態(tài)內(nèi)存分配等。
  實(shí)際上有些底層代碼根本沒(méi)這個(gè)資本提供這樣的“豪華裝備”,不過(guò)有這樣的思想還是很重要D……

Item 19 :設(shè)計(jì)class猶如設(shè)計(jì)type
----------------------------------------
 tag:class design
 
 ·小心設(shè)計(jì)類(lèi)的創(chuàng)建和銷(xiāo)毀方式。比如說(shuō)Item8和Item16
 ·認(rèn)真考慮如何區(qū)分類(lèi)的構(gòu)造函數(shù)和賦值(assignment)操作符。即初始化與賦值的差別。
 ·注意實(shí)現(xiàn)類(lèi)的傳值(passed by value)。這個(gè)實(shí)際上是在說(shuō)要注意拷貝構(gòu)造函數(shù)的實(shí)現(xiàn)。
 ·切勿忽略類(lèi)對(duì)非法輸入的處理。其實(shí)是要注意各種出錯(cuò)情況,是否需要拋出異常以及如何實(shí)現(xiàn)異常處理。
 ·需要審視類(lèi)所在的繼承體系。
  如果該類(lèi)有父類(lèi),那么必定要受到父類(lèi)的一些限制,特別是函數(shù)是否為虛構(gòu);如果該類(lèi)有子類(lèi),那么就要考慮是不是一些函數(shù)需要定義為虛函數(shù),比如說(shuō)析構(gòu)函數(shù)。
 ·謹(jǐn)慎實(shí)現(xiàn)類(lèi)對(duì)象與其他類(lèi)型對(duì)象的轉(zhuǎn)換。這一點(diǎn)稍有些復(fù)雜:如果有將T1轉(zhuǎn)換為T(mén)2的需求,就有隱式轉(zhuǎn)換和顯式轉(zhuǎn)換兩種方式。
  對(duì)于前者,可以編寫(xiě)一個(gè)(隱式的)轉(zhuǎn)換函數(shù)(參考Item15里面的隱式轉(zhuǎn)換咯~),或者是通過(guò)額外編寫(xiě)一個(gè)T2的構(gòu)造函數(shù)來(lái)實(shí)現(xiàn)T1向T2的轉(zhuǎn)換。
  對(duì)于后者,Scott說(shuō)寫(xiě)一個(gè)(顯式的)轉(zhuǎn)換函數(shù)就可以了。(同樣,在Item15里也有顯式轉(zhuǎn)換函數(shù)的例子)
 ·需要考慮該類(lèi)需要參與哪些運(yùn)算。很明顯,如果需要參與A運(yùn)算就要相應(yīng)定義類(lèi)的A運(yùn)算符函數(shù)。大師在這里提的另外一點(diǎn)是,這些運(yùn)算符號(hào)函數(shù)有些應(yīng)該是成員函數(shù),有些不應(yīng)該。原因在Item23、24、26【555我還沒(méi)看到,留空】
 ·不要提供不應(yīng)該暴露的標(biāo)準(zhǔn)函數(shù)。這里的標(biāo)準(zhǔn)函數(shù)指的是構(gòu)造/析構(gòu)/拷貝等等可能由編譯器“自愿”為你生成的函數(shù),如果不希望它們中的一些被外界調(diào)用,就聲明為私有(private)。沒(méi)印象了?降級(jí)到Item6重新學(xué)習(xí)~
 ·注意設(shè)計(jì)類(lèi)成員的訪問(wèn)權(quán)限。公有(public)、保護(hù)(protected)、私有(private)應(yīng)該用哪一種?有沒(méi)有需要定義友元?或者是干脆來(lái)一個(gè)類(lèi)中類(lèi)?都需要考慮。
 ·認(rèn)真審查類(lèi)的隱性限制。性能上的要求、使用資源的限制或是出錯(cuò)時(shí)的處理都有可能影響到類(lèi)的具體設(shè)計(jì)和實(shí)現(xiàn)。
 ·謹(jǐn)慎考慮類(lèi)的適用范圍。也就是說(shuō)如果某個(gè)設(shè)計(jì)會(huì)可能用在很多方面,適用于許多不同的實(shí)際對(duì)象。也許這個(gè)時(shí)候你需要設(shè)計(jì)的不是一個(gè)類(lèi),而是一個(gè)類(lèi)模板。
  最后一點(diǎn)其實(shí)應(yīng)該放在第一位:你真的需要定義一個(gè)類(lèi)嗎?如果僅僅是在繼承某類(lèi)的基礎(chǔ)上加一兩個(gè)成員,是不是非成員函數(shù)或模板就已經(jīng)夠了捏?

 第19招其實(shí)更像是個(gè)check list,在準(zhǔn)備動(dòng)手設(shè)計(jì)之前,一一比對(duì)打勾劃叉,應(yīng)該可以提前避免很多人間慘劇……

Item 20 : 用 傳const引用 替換  傳值
-------------------------------------------
 tag: const引用  值傳遞
 
  C++傳遞對(duì)象的時(shí)候默認(rèn)是傳值的(pass-by-value),而這樣的傳遞自然是昂貴的:這當(dāng)中包含了臨時(shí)對(duì)象的構(gòu)造/析構(gòu),以及臨時(shí)對(duì)象中的對(duì)象的構(gòu)造/析構(gòu),運(yùn)氣背點(diǎn)還可能有對(duì)象中的對(duì)象中的對(duì)象的構(gòu)造/析構(gòu)……(有好的不學(xué),去學(xué)C@#¥%)

 ·相對(duì)于傳“值”,一個(gè)更好的替代方法是傳“const引用”(pass-by-reference-to-const)。
 ·傳值與傳指針的一個(gè)區(qū)別是,通過(guò)傳值傳遞的對(duì)象并不是原來(lái)的對(duì)象,而是一個(gè)復(fù)制品,所以隨便你打它罵它,真身都不會(huì)受到影響。
 ·而通過(guò)傳指針的對(duì)象和原來(lái)的對(duì)象就是同一家伙,改動(dòng)一個(gè)另外一個(gè)也受到相同的影響。而這有時(shí)候并不是我們想要的結(jié)果。
 ·考慮到傳值代價(jià)太高,傳“const引用”就成了一個(gè)很好的替代品。

 ·傳“const引用”的另外一個(gè)好處在于避免了“剝皮問(wèn)題”(slicing problem,侯捷大師的版本是“對(duì)象切割問(wèn)題”,我用這個(gè)中文名字是為了更容易記住:))
  用傳值方式傳參的函數(shù),如果某參數(shù)的類(lèi)型是一個(gè)父類(lèi)對(duì)象,而實(shí)際傳遞的參數(shù)是一個(gè)子類(lèi)對(duì)象,只有該對(duì)象的父類(lèi)部分會(huì)被構(gòu)造并傳遞到函數(shù)中,子類(lèi)部分的成員,作為父類(lèi)對(duì)象的“皮”,就被血淋淋的剝掉了……
  而如果用傳“const引用”方式,就沒(méi)有這種慘無(wú)人道的狀況:本來(lái)父類(lèi)的指針就可以用來(lái)指向一個(gè)子類(lèi)對(duì)象,天經(jīng)地義。

 例外:對(duì)于內(nèi)置類(lèi)型(bulit-in type)對(duì)象以及STL中的迭代器、函數(shù)對(duì)象,Scott還是建議使用傳值方式傳遞,原因是他們本來(lái)就是被設(shè)計(jì)成適合傳值傳遞的。
 (個(gè)人觀點(diǎn):大師說(shuō):“……it's not unreasonable to choose pass-by-value。”,注意這里有句潛臺(tái)詞:其實(shí)對(duì)以上類(lèi)型用傳“const引用”方式傳遞也是可以的。)

 如果你認(rèn)為上面兩種情況可以用傳值傳遞是因?yàn)樗鼈儯热缯f(shuō)內(nèi)置類(lèi)型對(duì)象,的大小本來(lái)就小,進(jìn)而得出小數(shù)據(jù)類(lèi)型就可以用傳值傳遞,就打錯(cuò)特錯(cuò)了。小對(duì)象的構(gòu)造/析構(gòu)過(guò)程完全可能很恐怖。
 再退一步,哪怕某個(gè)類(lèi)型很小,它的構(gòu)造/析構(gòu)函數(shù)也簡(jiǎn)單到可以忽略不計(jì),我們還是不能以此斷定可以用傳值傳遞這種類(lèi)型的對(duì)象:因?yàn)榫幾g器往往會(huì)做出一些蠢事。書(shū)中的一個(gè)例子是,對(duì)于一些編譯器可以接受把一個(gè)double類(lèi)型對(duì)象存入寄存器,但是如果你給它一個(gè)只有一個(gè)double成員的對(duì)象交給它,它卻拒絕將該對(duì)象存入寄存器。(什么事讓編譯器插一手,不是問(wèn)題也有了問(wèn)題……)
 最后還有個(gè)理由,雖然某對(duì)象現(xiàn)在很小,可是隨著社會(huì)的發(fā)展人類(lèi)的進(jìn)步,有可能兩年后它就會(huì)變成一個(gè)龐然大物,到時(shí)候用傳值也會(huì)變得不合適。

 ·除了內(nèi)置類(lèi)型和STL的迭代器、函數(shù)對(duì)象外,其他的對(duì)象傳遞時(shí),用傳“const引用”代替?zhèn)髦蛋伞?



Item 21:  該換回對(duì)象時(shí)別返回它的reference
---------------------------------------------------
 tag: 

 如果一個(gè)函數(shù)可能返回一個(gè)對(duì)原來(lái)不存在的對(duì)象的引用,那么函數(shù)就要自己去創(chuàng)建這個(gè)對(duì)象:要么在棧上(stack)要么在堆上(heap)。

 第一種情況中,函數(shù)中定義了局部對(duì)象,然后返回對(duì)該對(duì)象的引用。對(duì)象在函數(shù)結(jié)束后自動(dòng)銷(xiāo)毀,引用指向無(wú)效的地址。

 第二種情況,函數(shù)使用new動(dòng)態(tài)創(chuàng)建了一個(gè)對(duì)象,然后返回對(duì)該對(duì)象的引用。粗看沒(méi)有問(wèn)題,因?yàn)檫@個(gè)返回的引用還是有效的。
  但是細(xì)想就會(huì)發(fā)現(xiàn):我們能確保這個(gè)對(duì)象被正確的收回(delete)嗎?
  書(shū)中舉了一個(gè)很好的例子:一個(gè)*運(yùn)算符函數(shù),接受兩個(gè)乘法運(yùn)算數(shù),返回一個(gè)積。
  如果在函數(shù)中動(dòng)態(tài)創(chuàng)建一個(gè)對(duì)象來(lái)存儲(chǔ)乘積,并返回對(duì)這個(gè)新對(duì)象的引用,那么下面的計(jì)算就會(huì)帶來(lái)內(nèi)存泄漏:
     Y=A*B*C
  因?yàn)樵谶@個(gè)“連續(xù)”乘法中,有兩個(gè)“乘積對(duì)象”被創(chuàng)建,但是我們丟失了第一次乘法創(chuàng)建的對(duì)象的指針。
  所以這樣的做法是不妥的。
  也許大師有被問(wèn)過(guò):那么對(duì)于第一種情況我們可不可以返回一個(gè)靜態(tài)(static)對(duì)象的引用?書(shū)中用了同樣的例子來(lái)回答:NO。
     if (A*B == C*D) {//..}
  如果返回靜態(tài)對(duì)象的引用,上面的判斷語(yǔ)句永遠(yuǎn)得到true值,因?yàn)?#8220;==”號(hào)兩邊的運(yùn)算結(jié)果是指向同一塊數(shù)據(jù)的引用。

 不知道是不是后面又有刨根問(wèn)題的學(xué)生追問(wèn):那我能不能用一個(gè)靜態(tài)對(duì)象的數(shù)組來(lái)存放不同此運(yùn)算的結(jié)果?大師懶得舉例子了,我猜想也沒(méi)必要:這樣的方案帶來(lái)的副作用及其開(kāi)銷(xiāo)本身就已經(jīng)大于原來(lái)要解決的問(wèn)題了吧?

 不要嘗試在函數(shù)中返回對(duì)局部對(duì)象(存儲(chǔ)于棧)的引用,也不要對(duì)動(dòng)態(tài)創(chuàng)建的對(duì)象(存儲(chǔ)于堆)做同樣的蠢事,而如果真有打算、非常渴望、十分想要返回對(duì)靜態(tài)對(duì)象的引用,在這么做之前也要考慮清楚會(huì)不會(huì)有上面例子中的情況出現(xiàn)。
 至少,返回對(duì)象不會(huì)有上面列出的種種錯(cuò)誤危險(xiǎn),僅僅是有可能帶來(lái)創(chuàng)建額外對(duì)象的開(kāi)銷(xiāo)而已,而這個(gè)開(kāi)銷(xiāo)的可能還有可能被排除,如果你用的編譯器足夠聰明的話(huà)。



Item 22:  將成員變量聲明為private
-----------------------------------------------------

 如果數(shù)據(jù)成員都是私有的,那么訪問(wèn)這些成員就只能通過(guò)函數(shù)進(jìn)行。于是用戶(hù)就不需要費(fèi)心考慮到底要用什么方式去訪問(wèn)數(shù)據(jù)成員:因?yàn)橹挥卸x了的函數(shù)可以用。
 通過(guò)定義數(shù)據(jù)成員為私有,可以實(shí)現(xiàn)函數(shù)來(lái)設(shè)計(jì)、約束或禁止對(duì)這些成員的各種訪問(wèn)(讀/寫(xiě)等)。而如果將其設(shè)為公有(public),你將無(wú)法得知你的成員會(huì)被誰(shuí)改動(dòng),也不知道會(huì)是怎樣的改動(dòng)。
 而更重要的好處是封裝(encapsulation):可以方便的通過(guò)修改函數(shù)來(lái)改變成員的訪問(wèn)方式;在成員被訪問(wèn)時(shí)通知其他對(duì)象;實(shí)現(xiàn)多線程中的同步等等。
 封裝的好處究其本質(zhì),是通過(guò)對(duì)用戶(hù)隱藏?cái)?shù)據(jù)成員來(lái)保證類(lèi)行為的一致性(class invariant)。因?yàn)榻涌诒怀蓡T訪問(wèn)函數(shù)限制了,類(lèi)的作者也為自己日后修改類(lèi)的實(shí)現(xiàn)留了后路:如果所有的成員都是公有的,對(duì)任何代碼的修改都有可能影響到外界的使用。(因此Scott說(shuō)“Public means unencapsulated, and practically speaking, unencapsulated means unchangeable, especially for classes that are widely used.”)
 那么可不可以聲明為保護(hù)(protected)呢?其實(shí)道理和前面的公有是一樣的。公有的成員對(duì)類(lèi)的外部完全開(kāi)放,而保護(hù)的成員對(duì)類(lèi)的繼承者完全開(kāi)放。這個(gè)就像兩個(gè)區(qū)間:(-infinity, +infinity) 和 (0, +infinity),兩者的大小是一樣的。

 從分裝的角度,只有兩種訪問(wèn)級(jí)別:私有,及其他。 
 
 

Item 23:  用 non-member、non-friend 替換 member 函數(shù)
------------------------------------------------------

 從面向?qū)ο蟮慕嵌葋?lái)看,非成員函數(shù)更有利于數(shù)據(jù)的封裝。
 
  一個(gè)數(shù)據(jù)成員被越少的代碼訪問(wèn)到,該成員的封裝程度就越高。越少函數(shù)可以直接訪問(wèn)一個(gè)數(shù)據(jù)成員,該成員的封裝程度就越高。
  類(lèi)的數(shù)據(jù)成員應(yīng)該定義為私有。如果這個(gè)前提成立,那么能夠訪問(wèn)一個(gè)數(shù)據(jù)成員的函數(shù)便只能是該類(lèi)的成員函數(shù),或是友元函數(shù)。
  于是為了更好的封裝數(shù)據(jù),在可以完成相同功能的前提下,應(yīng)該優(yōu)先考慮使用非成員并且非友元函數(shù)。
  這里的“非成員并且非友元函數(shù)”是針對(duì)數(shù)據(jù)成員所在的類(lèi)而言的,也就是說(shuō)這個(gè)函數(shù)完全可以是其他類(lèi)的成員,只要是不能直接訪問(wèn)那個(gè)數(shù)據(jù)成員就可以。

 從靈活性上來(lái)說(shuō),非成員函數(shù)更少編譯依賴(lài)(compilation dependency),也就更利于類(lèi)的擴(kuò)展。
  例:一個(gè)類(lèi)可能有多個(gè)成員函數(shù),可能有一個(gè)函數(shù)需要A.h,另外一個(gè)函數(shù)要包含B.h,那么在編譯這個(gè)類(lèi)時(shí)就需要同時(shí)包含A.h和B.h,也就是說(shuō)該類(lèi)同時(shí)依賴(lài)兩個(gè)頭文件。
   如果使用非成員函數(shù),這個(gè)時(shí)候就可以把這些依賴(lài)關(guān)系不同的函數(shù)分別寫(xiě)在不同的頭文件中,有可能這個(gè)類(lèi)在編譯時(shí)就不需要再依賴(lài)A.h或是B.h了。
   把這些非成員函數(shù)分散定義在不同頭文件中的同時(shí),需要用namespace關(guān)鍵字把它們和需要訪問(wèn)的類(lèi)放在一起。
  // code in class_a.h
  namespace  AllAboutClassA  {
     class  ClassA  { // ..};
     // ..
  }

  // code in utility_1.h
  // ..
  namespace  AllAboutClassA  {
     void  WrapperFunction_1() { // ..};
     // ..
  }
  // ..

  // code in utility_2.h
  // ..
  namespace  AllAboutClassA  {
     void  WrapperFunction_2() { // ..};
     // ..
  }
  // ..
 這樣一來(lái),雖然這些非成員和類(lèi)不“住在”一個(gè)頭文件里,它們的“心”還是在一起的(在同一個(gè)名字空間, namespace, 中)。
 
 如果有需要添加新的非成員函數(shù),我們要做的只是在相同的名字空間中定義這些函數(shù)就可以,那個(gè)類(lèi)絲毫不會(huì)被影響,也即所謂的易擴(kuò)展性吧。
 對(duì)于類(lèi)的用戶(hù)來(lái)說(shuō),這樣的實(shí)現(xiàn)方式(指用非成員函數(shù))就更加合理:
 因?yàn)樽鳛轭?lèi)的用戶(hù),需要擴(kuò)展類(lèi)的時(shí)候又不能去修改別人的類(lèi)(版權(quán)?安全性?或者根本就沒(méi)有源碼?),就算是通過(guò)繼承該類(lèi)的方式也不能訪問(wèn)父類(lèi)的私有數(shù)據(jù)。

Item 24:  若所有參數(shù)皆需類(lèi)型轉(zhuǎn)換,為此函數(shù)采用 non-member 函數(shù)
------------------------------------------------------
 tag:  operator
 
 若需要為某個(gè)函數(shù)的所有參數(shù)(包括被this指針?biāo)傅哪莻€(gè)隱喻參數(shù))進(jìn)行類(lèi)型轉(zhuǎn)換,這個(gè)函數(shù)應(yīng)該設(shè)為 non-member.
 ---------------------
 class Rational{
 public:
  Rational(int num = 0, int denominator = 1); //構(gòu)造函數(shù)刻意不為 explicit; 允許 int-to-Rational 隱式轉(zhuǎn)換
  ...
  const Rational operator* (const Rational& rhs) const;
 }
 
 Rational oneHalf(1, 2);
 result = oneHalf * 2; //right  → result = oneHalf.operator*(2);
 result = 2 * oneHalf; //wrong! → result = 2.operator*(oneHalf); → result = operator*(2, oneHalf);

 ---------------------
 const Rational operator*(const Rational& lhs, const Rational& rhs){..}  //non-member function.
 若函數(shù)不該成為member,不一定要成為friend.
 

Item 25:  考慮寫(xiě)出一個(gè)不拋異常的 swap 函數(shù)
------------------------------------------------------
 tag: 異常處理 
 ·當(dāng) std::swap 對(duì)你的類(lèi)型效率不高時(shí),提供一個(gè) swap 成員函數(shù),并確定函數(shù)不拋出異常。
 ·如果你提供一個(gè) member swap,也該提供一個(gè) non-member swap 用來(lái)調(diào)用前者,
  對(duì)于 classes(非 templates),請(qǐng)?zhí)鼗?std::swap;
 ·調(diào)用 swap 時(shí)應(yīng)針對(duì) std::swap 使用using 聲明式,然后調(diào)用 swap 并不帶任何“命名空間資格修飾”。
 ·為“用戶(hù)定義類(lèi)型”進(jìn)行std templates 全特化是好的,但千萬(wàn)不要嘗試在 std 內(nèi)加入某些對(duì) std 而言全新的東西。
 
 
 std::swap的缺省實(shí)現(xiàn):用了一個(gè)中間臨時(shí)對(duì)象,然后兩兩交換。
 缺省的方法很簡(jiǎn)單,而在一些情況下卻也很耗資源:比如需要交換的是一個(gè)很復(fù)雜龐大的對(duì)象時(shí),創(chuàng)建/拷貝大量數(shù)據(jù)會(huì)使得這種swap的效率顯得非常低下。
 --------------------------
 更加適應(yīng)的實(shí)現(xiàn)思路:

 在類(lèi)/模板類(lèi)(class/class template)中定義一個(gè)公有的swap成員函數(shù),這個(gè)函數(shù)負(fù)責(zé)實(shí)現(xiàn)真正的交換操作。同時(shí),這個(gè)函數(shù)不能拋出異常。
 用成員是因?yàn)榻粨Q操作中可能會(huì)需要訪問(wèn)/交換類(lèi)的私有成員;用公有(public)來(lái)限制是為了給下面的輔助函數(shù)(wrapper function)提供接口。
 至于不能拋出異常,有兩個(gè)原因:
  一是Item29中所提到的異常安全性(exception-safety)需要不拋出異常的swap來(lái)提供保障(更多細(xì)節(jié)就到拜讀29條的時(shí)候再記錄吧。)
  二是一般而言高效的swap函數(shù)幾乎都是對(duì)內(nèi)置類(lèi)型的交換,而對(duì)內(nèi)置類(lèi)型的操作是不會(huì)拋出異常的。
 
 1. 如果需要使用swap的是一個(gè)類(lèi)(而不是模板類(lèi)),就為這個(gè)類(lèi)全特化std::swap,然后在這個(gè)特化版本中調(diào)用第一步中實(shí)現(xiàn)的swap函數(shù)。
 
 class  AClass{
 public :
     void  swap(AClass &  theOtherA){
        using  std::swap;  // 這一句會(huì)在稍后的第3點(diǎn)提到
        //  通過(guò)調(diào)用swap來(lái)完成該類(lèi)的特有交換動(dòng)作
    }
 // ..
 }
 
 namespace  std{
     // 在std名字域內(nèi)定義一個(gè)全特化的swap
    template <>   // 這樣的定義說(shuō)明是全特化
     void  swap < AClass >  ( AClass &  a, AClass &  b){
       a.swap(b);
    }
 }
 如此一來(lái),用戶(hù)可以直接應(yīng)用同樣的swap函數(shù)進(jìn)行交換操作,而當(dāng)交換對(duì)象是需要特殊對(duì)待的AClass對(duì)象時(shí),也可以無(wú)差別的使用并得到預(yù)期的交換結(jié)果。

 2. 如果我們需要交換的是模板類(lèi),那么就不能用全特化std::swap的方法了,偏特化的std::swap也行不通,因?yàn)椋?br>  C++中不允許對(duì)函數(shù)進(jìn)行偏特化(只能對(duì)類(lèi)偏特化),也 就是說(shuō)不能寫(xiě)出下面的程序:

  namespace std{  
     // illegal code as C++ doesn't allow partial specialization for function templates
     template<typename T>
     void swap< AClassTemplate<T> >(AClassTemplate<T>& a, AClassTemplate<T>& b)
     {
        a.swap(b);
     }
  }

  std名字空間中的內(nèi)容都是C++標(biāo)準(zhǔn)委員會(huì)的老大們定義的,為了保證std內(nèi)部代碼的正常運(yùn)作,不允許往里頭添加任何新的模板、類(lèi)、方程,重載也不可以。
  雖然可以像1.那樣寫(xiě)出全特化的模板函數(shù),但是企圖在std的名字空間添加以下重載的swap(這種重載變相實(shí)現(xiàn)了函數(shù)的偏特化)(雖然你可以通過(guò)編譯,但是會(huì)埋下隱患):

  namespace std{
     template <typename T>
     void swap (AClass<T>& a, AClass<T>& b)
     { a.swap(b);}
  }

  給自己的一個(gè)小提醒:因?yàn)楹瘮?shù)名swap后沒(méi)有<>,所以不是偏特化,而是對(duì)
  namespace std{
     template<class _Ty> inline
     void swap(_Ty& _X, _Ty& _Y)
     {/*..*/}
  }
  的重載而已。

 基于上面兩個(gè)原因,一個(gè)變通的方法是在該模板類(lèi)所在的名字空間中編寫(xiě)一個(gè) 非成員的函數(shù)模板來(lái)調(diào)用這個(gè)公有的接口:

  namespace AClassSpace{
     template <typename T>
     void swap (AClass<T>& a, AClass<T>& b)
     { a.swap(b);}
  }  
  在限定的名字空間中實(shí)現(xiàn)函數(shù),是為了避免“污染”全局的名字空間。而且,不同的名字空間都可以使用一樣的函數(shù)名字而不會(huì)有沖突。
  基于前面第23課所學(xué),使用非成員函數(shù)也是應(yīng)該的了。
  至于為什么要函數(shù)模板,那就匪常D簡(jiǎn)單:因?yàn)橐粨Q的是模板@#¥%

 pimpl也即pointer to implementation,當(dāng)需要交換兩個(gè)復(fù)雜且臃腫的對(duì)象時(shí),可以先用兩個(gè)指針?lè)謩e指向著兩個(gè)對(duì)象
 之后對(duì)這些對(duì)象的操作,包括交換,就只需要通過(guò)這兩個(gè)指針來(lái)進(jìn)行(交換兩個(gè)指針的值便實(shí)現(xiàn)了對(duì)象的交換)。

 

 

posted on 2010-03-15 22:50 Euan 閱讀(532) 評(píng)論(0)  編輯 收藏 引用 所屬分類(lèi): C/C++
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲欧美国产一区二区三区| 免费成人黄色| 亚洲私人影院| 极品裸体白嫩激情啪啪国产精品| 欧美视频专区一二在线观看| 欧美激情第8页| 欧美视频1区| 国产精品爽爽爽| 国产午夜精品久久| 黄色小说综合网站| 亚洲精品一区二区三| 在线天堂一区av电影| 欧美在线观看一区二区| 久久深夜福利免费观看| 91久久线看在观草草青青| 日韩天堂av| 性欧美video另类hd性玩具| 新片速递亚洲合集欧美合集| 蜜桃av综合| 国产精品美女久久久久久2018| 国产一区二区三区久久| 亚洲精品永久免费精品| 欧美亚洲一区二区在线| 久久字幕精品一区| 亚洲精品一区在线观看| 欧美在线精品一区| 欧美韩国在线| 国外成人在线视频| 亚洲欧美成人一区二区在线电影 | 久久黄色网页| 欧美成人综合一区| 国模一区二区三区| 亚洲婷婷综合久久一本伊一区| 久久精品色图| 夜夜嗨av一区二区三区中文字幕 | 亚洲美女视频在线免费观看| 欧美在线一级va免费观看| 亚洲一区观看| 亚洲一区综合| 免费美女久久99| 国产精品拍天天在线| 亚洲国产精品一区二区第一页| 亚洲一区三区在线观看| 亚洲激情第一区| 久久久久综合一区二区三区| 国产精品白丝黑袜喷水久久久| 亚洲国产成人午夜在线一区 | 亚洲一区二区三区乱码aⅴ蜜桃女| 亚洲国产欧美一区二区三区久久| 亚洲综合视频网| 日韩午夜免费视频| 欧美国产综合| 亚洲人成小说网站色在线| 久久漫画官网| 久久精品国产亚洲高清剧情介绍| 国产精品视频免费在线观看| 在线中文字幕不卡| 亚洲精品欧美在线| 欧美日韩国产综合一区二区| 亚洲精品日韩综合观看成人91| 欧美aⅴ99久久黑人专区| 久久成人免费| 亚洲丁香婷深爱综合| 蜜臀av一级做a爰片久久| 欧美一区二区三区男人的天堂| 国产美女精品免费电影| 欧美一二三区精品| 亚洲欧美日韩专区| 国产夜色精品一区二区av| 欧美中文字幕| 久久精品国产清自在天天线| 在线播放国产一区中文字幕剧情欧美| 久久综合久久久| 免费成人激情视频| 一区二区三区你懂的| 亚洲视频999| 国产一区二区精品久久91| 久久精品视频免费播放| 久久琪琪电影院| 99xxxx成人网| 亚洲午夜视频在线| 国内精品视频在线播放| 免费不卡视频| 欧美日韩免费观看一区二区三区| 亚洲视频二区| 久久av红桃一区二区小说| 亚洲大片av| 在线亚洲激情| 精品成人一区二区三区| 亚洲欧洲综合| 国产亚洲毛片| 亚洲国产黄色片| 国产精品专区h在线观看| 美女网站在线免费欧美精品| 欧美日韩 国产精品| 欧美一站二站| 欧美精品成人| 久久九九久久九九| 欧美久久成人| 久久尤物视频| 欧美视频在线一区二区三区| 久久久久久久波多野高潮日日| 欧美+日本+国产+在线a∨观看| 午夜免费日韩视频| 欧美va亚洲va香蕉在线| 欧美一区二区三区的| 欧美成人黑人xx视频免费观看 | 欧美激情国产精品| 国产欧美精品日韩精品| 亚洲国产一区二区a毛片| 国产日韩在线不卡| 亚洲欧美日韩人成在线播放| 久久精品国产一区二区电影 | 激情成人av在线| 亚洲一区二区动漫| 99精品久久久| 狂野欧美一区| 久久精品国产99精品国产亚洲性色 | 亚洲一区二区成人| 一本久道久久综合婷婷鲸鱼| 久久久伊人欧美| 久久xxxx| 国产欧美日韩视频一区二区三区| 亚洲精品国产品国语在线app| 在线成人黄色| 久久精品欧美| 久久精品一区二区三区不卡牛牛| 欧美午夜激情视频| 亚洲精品视频在线| 999在线观看精品免费不卡网站| 久久婷婷综合激情| 免费成人黄色av| 影音先锋中文字幕一区| 久久久久久婷| 欧美gay视频| 亚洲激情视频在线观看| 久热re这里精品视频在线6| 噜噜噜噜噜久久久久久91| 国产一区在线看| 久久精品亚洲一区| 美女免费视频一区| 亚洲电影中文字幕| 欧美顶级艳妇交换群宴| 亚洲欧洲综合另类| 中国亚洲黄色| 国产精品网站视频| 羞羞答答国产精品www一本| 久久精品五月| 在线看成人片| 欧美激情精品久久久久久大尺度| 亚洲韩日在线| 亚洲一区二区三区精品视频| 国产精品视频福利| 久久国产精品久久w女人spa| 欧美v日韩v国产v| 日韩视频在线永久播放| 国产精品magnet| 欧美亚洲一级片| 欧美国产第二页| 亚洲神马久久| 国产亚洲一本大道中文在线| 美日韩精品视频免费看| 一本到12不卡视频在线dvd| 午夜日韩av| 亚洲高清在线精品| 欧美日韩一区二区三区在线观看免 | 欧美.www| 一区二区三区视频观看| 西西裸体人体做爰大胆久久久| 久久精品视频在线看| 亚洲激情成人网| 欧美午夜精品一区| 久久嫩草精品久久久精品| 99在线视频精品| 裸体歌舞表演一区二区| 亚洲午夜电影在线观看| 国产亚洲综合精品| 欧美日韩国语| 久久天天躁狠狠躁夜夜爽蜜月| 日韩视频一区二区三区在线播放免费观看| 性久久久久久久久| 亚洲精品老司机| 国产午夜精品一区二区三区欧美| 欧美凹凸一区二区三区视频| 欧美在线91| 亚洲一区二区精品视频| 亚洲国产福利在线| 久久午夜精品一区二区| 亚洲欧美大片| 99re热精品| 亚洲激情女人| 影院欧美亚洲| 国产日产精品一区二区三区四区的观看方式 | 亚洲图片欧洲图片av| 欧美成人免费一级人片100| 香蕉久久夜色精品国产使用方法| 亚洲精品欧美在线| 在线观看国产成人av片| 国产在线国偷精品产拍免费yy| 欧美视频导航|