1,、 文件的屬性以及開始和結(jié)束注釋標(biāo)記 a) 在每一個(gè)文件的頭部用注釋填寫:章節(jié)號(hào):文件名,以及該文件所完成的功能,。 b) 如何一個(gè)文件是頭文件,,則什么也不用做 c) 如果這個(gè)文件中的程序中不含main()(即,不含主程序的.cpp的文件),,這必須與其他部分連接,,所以,在注釋行的文件名后添加:{O} d) 如果,,文件是主程序(含有main()函數(shù)),但是需要和其他部分連接,,則有獨(dú)立的//{L}開頭的行,并在{L}后填寫所要連接的文件名(不含主程序的.cpp文件的名字) 2,、 圓括號(hào),,大括號(hào)縮排 a) 單行定義常用于內(nèi)聯(lián)函數(shù) b) 函數(shù)以及類的縮排如下: Fun(){ /*Bodyhere */: } 3、 標(biāo)示符命名 a) 如果標(biāo)示符是一個(gè)類:則第一個(gè)字母必須大寫 b) 如果標(biāo)示符是一個(gè)函數(shù)名或者變量名:則第一個(gè)字母必須小寫 c) 剩余部分由一個(gè)或多個(gè)單詞構(gòu)成每個(gè)單詞第一個(gè)字母必須大寫 d) 編譯時(shí)常量(const,,#define),,標(biāo)示符的所有字母都必須大寫 4、 頭文件的包含順序 C++編程思想里面倡導(dǎo)用“最特殊到最一般的”的順序,,即,,首先為本地文件,接著為 自己的工具文件,,最后,,庫(kù)文件。由于函數(shù)調(diào)用的順序是按照頭文件的包含順序的來的,。從而,,使得用戶的函數(shù)不被系統(tǒng)的以及第三方的庫(kù)文件的函數(shù)所沖掉??梢?,讓用戶程序員清晰的指導(dǎo)自己定義的接口是否和第三方或者系統(tǒng)的庫(kù)函數(shù)所沖突。 另外,,Google C++編程規(guī)范倡導(dǎo)的剛好相反:“從最一般到最特殊”,,所以,,能大量減少隱藏的頭文件依賴。同時(shí),,在其中倡導(dǎo)應(yīng)該首先包含首選頭文件,,即a.cpp文件中包含頭文件時(shí)應(yīng)該是首先包含a.h文件。 綜上,,C++編程思想的編程風(fēng)格雖有缺點(diǎn),,但是好處還是很多。 5,、 在頭文件中包含警衛(wèi) 總是在頭文件中包含警衛(wèi),,從而,避免單個(gè).cpp文件期間一個(gè)頭文件被多次包含,。如下: //IncludeGuard.h #ifndefINCLUDEGUARD_H #defineINCLUDEGARD_H //Bodyof header file here… #endif//INCLUDEGARD_H 從中可以看出,,警衛(wèi)以頭文件名為基礎(chǔ),將文件名的字母大寫,,然后用下劃線代替’.’,。 6、 使用名字空間 在頭文件中,,必須保證其中沒有包含任何有“污染”的名字空間,,即如果改變函數(shù)或者 類外面的名字空間,將導(dǎo)致包含刺頭文件的所有文件的改變,。所以,,在C++中不允許在函數(shù)的聲明外面有任何using聲明,同時(shí)不允許在頭文件中有全局的using聲明,。 7,、 使用“前置條件”和后置條件 Require()和assure()都在require.h中,在“核心函數(shù)”開始之前,,用檢查前置條件來保證 “核心函數(shù)”執(zhí)行所需要的條件都是否滿足,,而,核心函數(shù)執(zhí)行完畢之后使用后置條件來檢查核心函數(shù)是否已經(jīng)正確執(zhí)行,,且返回正確的結(jié)果,。 第十八章——編程準(zhǔn)則 1. 首相讓程序運(yùn)行,然后在追求速度,。即使這段程序非常重要,而且,,是我們的瓶頸,。不要優(yōu)化,首先用盡可能簡(jiǎn)單的設(shè)計(jì)讓程序可以運(yùn)行,,如果速度不滿足要求再對(duì)其進(jìn)行優(yōu)化,。我們總能夠發(fā)現(xiàn)“我們的”瓶頸并不是問題的所在,。節(jié)省時(shí)間做真正有意義的事。 2. 編寫簡(jiǎn)潔優(yōu)美的程序有很多潛在的好處,。簡(jiǎn)潔優(yōu)美的程序不僅易讀,,易調(diào)試,而且,,易于理解和維護(hù),。這正是能帶來經(jīng)濟(jì)利益的地方。最初看啦簡(jiǎn)潔優(yōu)美的程序會(huì)使我們的效率變低,,但是,,等到我們的程序能夠無縫地嵌入到系統(tǒng)時(shí),我們發(fā)現(xiàn)一切都是值得的,,特別當(dāng)修改我們的程序時(shí)更將淋漓的體現(xiàn),。 3. 分而治之。如果,,感到問題復(fù)雜,,是猜測(cè)程序的最基本的操作,為最難的部分創(chuàng)造一個(gè)對(duì)象——書寫代碼并且應(yīng)用這個(gè)對(duì)象,,然后將這個(gè)最難的部分嵌入其他的對(duì)象,,等等。 4. 不用C++重寫C的代碼,,除非我們需要做功能上大的調(diào)整(能用即不重做),。但用C++編譯器編譯C代碼卻好處多,可以發(fā)現(xiàn)代碼中潛在的問題,。 5. 如果有許多C代碼需要改變,,首先隔離不需要修改的代碼,最好將那些函數(shù)打包成“API”的靜態(tài)成員函數(shù),。然后集中精力到要修改的代碼,,將它們精化成類以使以后的維護(hù)修改更容易。 6. 要區(qū)別類的創(chuàng)建者和類的使用者(客戶程序員),。類的使用者不需要也不想知道類的內(nèi)部是如何實(shí)現(xiàn)的,。被創(chuàng)建的類可以被沒有經(jīng)驗(yàn)的程序員使用,而且要工作良好,,庫(kù)只是在透明的情況下才會(huì)容易使用,。 7. 創(chuàng)建類時(shí),要盡可能用有意義的類名,。目標(biāo)是創(chuàng)建一個(gè)盡可能簡(jiǎn)單接口,,這可以通過函數(shù)重載和默認(rèn)參數(shù)的方法實(shí)現(xiàn)。 8. 數(shù)據(jù)隱藏允許我們不破壞用戶代碼下隨心所欲的修改代碼,。所以,,我們把對(duì)象的成員盡可能的定義為private,,而只讓接口的部分為public,而且總是使用函數(shù)而不是數(shù)據(jù),。如果類的使用者不需要調(diào)用這個(gè)函數(shù),,那么讓這個(gè)函數(shù)也成為private,如果類的一部分讓派生類可見,,就定義為protected,,并且提供一個(gè)接口不是直接暴露數(shù)據(jù),這樣,,實(shí)現(xiàn)部分的改變將對(duì)派生類產(chǎn)生最小的影響,。 9. 不要陷入分析癱瘓中。有些東西只有在編程時(shí)才能學(xué)到并使各系統(tǒng)正常,。C++有內(nèi)建的防火墻,,讓它為我們服務(wù),在類或一組類中的錯(cuò)誤不會(huì)破壞整個(gè)系統(tǒng)的完整性,。 10. 我們的分析和設(shè)計(jì)至少要在系統(tǒng)中創(chuàng)建類,、它們的公共接口、它們與其他類的關(guān)系,、特殊的基類,。如果我們的方法產(chǎn)生的東西比這些更多,就應(yīng)當(dāng)問問自己,,是不是所有的成分在程序設(shè)計(jì)的整個(gè)生命周期內(nèi)都是有價(jià)值的,,如果不是,將會(huì)增加我們的維護(hù)開銷,。許多設(shè)計(jì)方法并不大奏效,,這是事實(shí)。 11. 首先寫測(cè)試代碼(在寫類之前),,并和代碼一起提交,,運(yùn)用makefile或其他工具使運(yùn)行測(cè)試自動(dòng)化。這樣在運(yùn)行測(cè)試代碼之前就可以自動(dòng)校驗(yàn)改變,,迅速發(fā)現(xiàn)錯(cuò)誤,。因?yàn)槲覀儞碛袡z測(cè)錯(cuò)誤的體系,所以,,當(dāng)發(fā)現(xiàn)需要修改代碼時(shí),,會(huì)更大膽地盡心嘗試。 12. 首先寫測(cè)試代碼(在寫類之前)可以保證類設(shè)計(jì)的完整性,。如果不懈測(cè)試代碼,,就不知道我們的類能做什么。另外,,寫測(cè)試代碼的過程會(huì)使我們想到類中所需要的其他特性或約束條件——這些特性或約束條件通常在設(shè)計(jì)時(shí)是不易覺察的,。 13. 軟件工程的基本原則:所有的問題都可以通過引進(jìn)一個(gè)額外的間接層來簡(jiǎn)化。這是抽象方法額基礎(chǔ),,而抽象是面向?qū)ο缶幊痰氖滓卣鳌?/SPAN> 14. 盡可能地原子化類,。也就是每一個(gè)類都有一個(gè)單一、清楚地目的,。如果,,我們?cè)O(shè)計(jì)的類或我們?cè)O(shè)計(jì)的系統(tǒng)過于復(fù)雜,就應(yīng)該將所有復(fù)雜的類分解成多個(gè)簡(jiǎn)單的系統(tǒng),。 15. 注意較長(zhǎng)的成員函數(shù)定義,,長(zhǎng)的復(fù)雜的函數(shù)難于維護(hù),而且很可能這個(gè)函數(shù)自己做了太多的事,。如果看到這樣的一個(gè)函數(shù),,至少預(yù)示著應(yīng)該分解為幾個(gè)函數(shù),甚至預(yù)示著應(yīng)該創(chuàng)造一個(gè)新類,。 16. 注意長(zhǎng)的參數(shù)表,,這樣的函數(shù)調(diào)用會(huì)難寫、難讀,、難于維護(hù),。應(yīng)該把這個(gè)函數(shù)改成一個(gè)合適的類,用對(duì)象作為參數(shù)傳遞,。 17. 不要自我重復(fù),。如果一段代碼在派生類的許多函數(shù)中重復(fù)出現(xiàn),就把這段代碼放在基類的一個(gè)單一的函數(shù)中然后在派生類中調(diào)用它,。這樣既節(jié)省了代碼空間,,又使將來的修改容易傳播。我們可以用內(nèi)聯(lián)函數(shù)來提高效率,。有時(shí)我們會(huì)發(fā)現(xiàn)這種通用代碼會(huì)為我們的接口添加有用的功能,。 18. 注意switch和if-else語(yǔ)句。他們是典型的類型檢查編碼的指示符,。意味著程序運(yùn)行的情況和我們的類型信息有關(guān),。(實(shí)際的類型也許不是我們最初看起來的類型)我們通常可以將這些代碼轉(zhuǎn)換成繼承或多態(tài),,多態(tài)會(huì)為我們進(jìn)行類型檢查,,使程序可靠和已與擴(kuò)展。 19. 從設(shè)計(jì)的角度,,尋找并區(qū)分那些變化和不變的成分,。也就是在系統(tǒng)中尋找那些修改時(shí)不需要重新設(shè)計(jì)的成分,把他們封裝到一個(gè)類中,。 20. 注意不同點(diǎn),。兩個(gè)語(yǔ)義上不同的對(duì)象可能有同樣的操作或反應(yīng),,自然就會(huì)試著把一個(gè)作為另一個(gè)的子類以便利用繼承性的好處。這就叫差異,,但并沒有充分的理由來強(qiáng)制這種并不存在的父子關(guān)系,。一個(gè)好的解決辦法是產(chǎn)生一個(gè)共同的父類:它包含兩個(gè)子類——這可能要多占一點(diǎn)空間,但我們可以從繼承中獲益,,并且可能對(duì)這種設(shè)計(jì)有重要發(fā)現(xiàn),。 21. 注意在繼承過程中的限制。最清晰地設(shè)計(jì)是向被繼承者加入新的功能,,而如果在繼承過程刪除了原有功能,,而不是加入新功能,那這個(gè)設(shè)計(jì)就值得懷疑了,。但這也不是絕對(duì)的,,如果我們正在與一個(gè)老的類庫(kù)打交道,對(duì)已有的類在子類中進(jìn)行限制可能更有效,,而不必重建一套類層次來使我們的新類適應(yīng)新的應(yīng)用,。 22. 不要用子類去擴(kuò)展基類的功能。如果一個(gè)類接口部分很關(guān)鍵的話,,應(yīng)當(dāng)把它放在基類中,,而不是在繼承中加入。如果我們正在用繼承來添加成員函數(shù),,我們可能應(yīng)該重新考慮我們的設(shè)計(jì),。 23. 一個(gè)類一開始時(shí)接口部分應(yīng)盡可能小而精。在類使用過程中,,我們會(huì)發(fā)現(xiàn)需要擴(kuò)展類的接口,。然而一個(gè)類一旦投入使用,我們要想減少接口部分,,就會(huì)影響那些使用了該類的代碼,,但如果我們我們需要增加函數(shù)則不會(huì)有影響,一切正常,,只需要重新編譯一下即可,。但即使用新的成員函數(shù)取代了原來的功能,也不要去改正原有接口(如果我們?cè)敢獾脑?,可以再低層將兩個(gè)函數(shù)合并,。)如果我們需要對(duì)一個(gè)已有的函數(shù)增加參數(shù),我們可以讓原來的參數(shù)保持不變,,把所有新參數(shù)作為默認(rèn)參數(shù),,這樣不會(huì)妨礙對(duì)該函數(shù)已有的調(diào)用。 24. 大聲朗讀我們的類,確保他們是合理的,。讀基類時(shí)用“is-a”,讀成員對(duì)象時(shí)用“has-a”,。 25. 在決定是用繼承還是用組合時(shí),問問自己是不是需要向上類型轉(zhuǎn)換到基類,。如果不需要,,就用組合(成員對(duì)象)而不用繼承。這樣可以減少多重繼承的可能,。如果我們選擇繼承,用戶會(huì)認(rèn)為他們被假設(shè)向上類型轉(zhuǎn)換,。 26. 有時(shí)我們?yōu)榱嗽L問基類中的protected成員而采用繼承,。這可能導(dǎo)致一個(gè)可察覺的對(duì)多重繼承的需求。如果我們不需要向上類型轉(zhuǎn)換,,首先導(dǎo)出一個(gè)新類來完成保護(hù)成員的訪問,,然后把這個(gè)新類作為一個(gè)成員對(duì)象,放在需要用到它的所有對(duì)象中去,。 27. 一個(gè)典型的基類僅僅是它的派生類的一個(gè)接口,。當(dāng)我們創(chuàng)建一個(gè)基類時(shí),默認(rèn)情況下讓成員函數(shù)都成為純虛函數(shù),。析構(gòu)函數(shù)也可以是純虛函數(shù)(強(qiáng)制派生類對(duì)它重新定義),但記住要給析構(gòu)函數(shù)一個(gè)函數(shù)體,,因?yàn)槔^承關(guān)系中所有的析構(gòu)函數(shù)總是被調(diào)用。 28. 當(dāng)我們?cè)陬愔蟹乓粋€(gè)虛函數(shù)時(shí),,讓這個(gè)類的所有函數(shù)都成為虛函數(shù),,并在類中定義一個(gè)虛析構(gòu)函數(shù)。只有當(dāng)我們要求高效時(shí),,而且分析工具指出應(yīng)該這樣做,,再把virtual關(guān)鍵字去掉。 29. 用數(shù)據(jù)成員表示值的變化,,用虛函數(shù)表示行為的變化,。如果我們發(fā)現(xiàn)一個(gè)類中有幾個(gè)狀態(tài)變量和幾個(gè)成員函數(shù),而成員函數(shù)在這些變量的作用下改變行為,,我們可能要重新設(shè)計(jì)它,,用子類和虛函數(shù)來區(qū)分這種不同的作用。 30. 如果我們必須做一些不可移植的事,,對(duì)這種服務(wù)做一個(gè)抽象并將它定位在一個(gè)類的內(nèi)部,,這個(gè)額外的間接層可防止這種不可移植性影響我們的整個(gè)程序。 31. 盡量不用多重繼承,。這可幫助我們擺脫困境,,尤其是修復(fù)我們無法控制的類的借口時(shí)。除非我們是一個(gè)經(jīng)驗(yàn)相當(dāng)豐富的程序員,否則不要在系統(tǒng)中設(shè)計(jì)多重繼承,。 32. 不要用私有繼承,。雖然C++中可以有私有繼承,而且似乎在某些場(chǎng)合下很有用,,但它和運(yùn)行時(shí)類型識(shí)別一起使用時(shí),,常常引起語(yǔ)義的模棱兩可。我們可以用一個(gè)私有成員對(duì)象來代替私有繼承,。 33. 如果兩個(gè)類因?yàn)橐恍┖瘮?shù)的關(guān)系(如容器和迭代器)而聯(lián)系在一起,,使一個(gè)類設(shè)為公有并將另一個(gè)類包含成友元。這不僅強(qiáng)調(diào)二者之間的聯(lián)系,,而且允許一個(gè)類的名字嵌入到另一個(gè)類中復(fù)用,。標(biāo)準(zhǔn)C++通過在每個(gè)容器類中定義嵌入的迭代器類,為容器提供了通用接口,。嵌入的另一個(gè)原因是可以作為私有運(yùn)行的一部分,。這里,嵌入比類之間的聯(lián)系提供了更大的運(yùn)行隱藏,,而且防止出現(xiàn)上面提到的名字空間污染,。 34. 運(yùn)算符重載僅僅是“語(yǔ)法糖”:另一種函數(shù)調(diào)用方法。如果重載一個(gè)運(yùn)算符不會(huì)使類的接口更清楚,、更易于使用,,就不要重載它。一個(gè)類只創(chuàng)建一個(gè)自動(dòng)類型轉(zhuǎn)換運(yùn)算符,。 35. 首先保證程序能運(yùn)行,,然后再考慮優(yōu)化。特別是,,不要急于寫內(nèi)聯(lián)函數(shù),、使一些函數(shù)為非虛函數(shù)或者緊縮代碼以提高效率。這些在我們開始構(gòu)建系統(tǒng)時(shí)都不用考慮,。我們開始的目標(biāo)應(yīng)該是證明設(shè)計(jì)的正確性,,除非設(shè)計(jì)要求一定的效率。 36. 不要讓編譯器來為我們產(chǎn)生構(gòu)造函數(shù),、析構(gòu)函數(shù)或operator=,。類的設(shè)計(jì)者應(yīng)該明確地說出類應(yīng)該做什么,并完全控制這個(gè)類,。如果我們不想要拷貝構(gòu)造函數(shù)或operator=,就把他們聲明為私有的,。記住,只要我們產(chǎn)生了任何構(gòu)造函數(shù),,就防止了默認(rèn)構(gòu)造函數(shù)被生成,。 37. 如果我們的類中包含指針,我們必須產(chǎn)生拷貝構(gòu)造函數(shù)、operator=和析構(gòu)函數(shù),,以使類運(yùn)行正常,。 38. 當(dāng)為派生類寫拷貝構(gòu)造函數(shù)時(shí),記住要顯示調(diào)用基類的拷貝構(gòu)造函數(shù),。如果不這樣做,,基類會(huì)調(diào)用默認(rèn)構(gòu)造函數(shù),可能這不是我們所想要的情形,。要調(diào)用基類拷貝構(gòu)造函數(shù),,用以下方式將它傳給派生類:Derived(const Derived& d):Base(d){//... 39. 當(dāng)為派生類寫賦值操作符時(shí),記住顯示調(diào)用基類版本,。如果不如此,,就不會(huì)起作用。應(yīng)用基類的名字和作用域操作符,,調(diào)用基類的賦值運(yùn)算符: Derived&operator=(const Derived& d){ Base::operator=(d); 40. 為了減少大項(xiàng)目開發(fā)過程中的重復(fù)編譯,應(yīng)使用句柄類/Cheshire cat技術(shù),,只有需要提高運(yùn)行效率時(shí)才把它去掉,。 41. 避免用預(yù)處理器??梢杂贸A縼泶嬷?,用內(nèi)聯(lián)函數(shù)代替宏。 42. 保持范圍盡可能地小,,這樣我們的對(duì)象的可見性和生命周期也就盡可能地小,。這就減少了錯(cuò)用對(duì)象和隱藏難以發(fā)現(xiàn)的錯(cuò)誤的可能性。 43. 避免使用全局變量,。盡可能把數(shù)據(jù)放在類中,。全局函數(shù)的存在可能性要比全局變量大。一個(gè)全局函數(shù)作為一個(gè)類的靜態(tài)成員更合適,。 44. 如果我們需要聲明一個(gè)來自庫(kù)中的類或函數(shù),,應(yīng)該包含一個(gè)頭文件的方法。而不要用一個(gè)不完全類型指定的方法,,如:創(chuàng)建一個(gè)函數(shù)來寫道ostream中: Class ostream,。 應(yīng)該是:#include <iostream> 當(dāng)我們創(chuàng)建我們自己的類的時(shí)候,在只需用到指針的情況下,,如果一個(gè)庫(kù)很大,,應(yīng)該給用戶提供一個(gè)頭文件的簡(jiǎn)寫形式,文件中包含又不完全的類型說明(就是類型名聲明),它可以提高編譯器的速度,。 45. 當(dāng)選擇重載運(yùn)算符的返回值類型時(shí),,要考慮表達(dá)式連成一串時(shí)可能出現(xiàn)的情況:當(dāng)定義operator=時(shí),應(yīng)記住x=x。要對(duì)左值返回一個(gè)拷貝或一個(gè)引用,,這樣才能用在串連表達(dá)式中,。 46. 當(dāng)寫一個(gè)函數(shù)時(shí),我們的第一選擇是用const引用來傳遞參數(shù),。只要我們不需要修改正在被傳遞進(jìn)入的對(duì)象,,這種方式是最好的。因?yàn)樗兄鴤髦捣绞降暮?jiǎn)單,,但不需要費(fèi)時(shí)的構(gòu)造和析構(gòu)來產(chǎn)生局部對(duì)象,,而這在傳值方式時(shí)是不可避免的。通常我們?cè)谠O(shè)計(jì)和構(gòu)建我們的系統(tǒng)時(shí)不用注意效率問題,,但養(yǎng)成這種習(xí)慣仍是件好事,。 47. 當(dāng)心臨時(shí)變量。當(dāng)調(diào)整效率時(shí),,要注意臨時(shí)創(chuàng)建的對(duì)象,,尤其是用運(yùn)算符重載時(shí)。如果我們的構(gòu)造函數(shù)和析構(gòu)函數(shù)很復(fù)雜,,創(chuàng)建和銷毀臨時(shí)對(duì)象就很費(fèi)時(shí),。當(dāng)從一個(gè)函數(shù)返回一個(gè)值時(shí),總是應(yīng)在return語(yǔ)句中調(diào)用析構(gòu)函數(shù)來“就地”產(chǎn)生一個(gè)對(duì)象,。return MyType(i,j);這優(yōu)于 MyTypex(i,j); return x; 48. 當(dāng)產(chǎn)生構(gòu)造函數(shù)時(shí),,要考慮到異常情況,在最好的情況下,,構(gòu)造函數(shù)只是拋出異常,,其次是:類只從健壯的類被組合和繼承,所以當(dāng)拋出異常時(shí)它們會(huì)自動(dòng)清除它們所作的一切,。如果我們必須使用裸指針,,我們應(yīng)該負(fù)責(zé)捕獲自己的異常,然后在我們的構(gòu)造函數(shù)拋出異常以前釋放所有指針指向的資源,。如果一個(gè)構(gòu)造函數(shù)無法避免失敗,,最好的方法是拋出異常。 49. 在我們的構(gòu)造函數(shù)中只做一些最必要的事情,,這不僅使構(gòu)造函數(shù)的調(diào)用有較低的時(shí)間花費(fèi),,而且我們的構(gòu)造函數(shù)更少地拋出異常和引用問題。 50. 析構(gòu)函數(shù)的作用是釋放在對(duì)象的整個(gè)生命期內(nèi)分配的所有資源,,而不僅僅是在創(chuàng)建期間,。 51. 使用異常層次,最好從標(biāo)準(zhǔn)C++異常層次中繼承,,并作為公共類嵌入能拋出異常的類中,。捕獲異常的人然后可以確定異常的類型,。如果我們加上新的派生異常,已存在的客戶代碼還是通過基類來捕獲這個(gè)異常,。 52. 用值來拋出異常,,用引用來捕獲異常。讓異常處理機(jī)制處理內(nèi)存管理,。如果我們拋出一個(gè)指向在堆上產(chǎn)生的異常的指針,,則捕獲者必須破壞這個(gè)異常,這事一種不利的耦合,。如果我們用值來捕獲異常,,我們需要額外的構(gòu)造和析構(gòu),更糟的是,,我們的異常對(duì)象的派生部分可能在以值向上類型轉(zhuǎn)換時(shí)被切片,。 53. 除非確有必要,否則不要寫自己的類模板,。先查看一個(gè)標(biāo)準(zhǔn)模板庫(kù),,然后查問創(chuàng)建特殊工具的開發(fā)商。當(dāng)我們熟悉了這些產(chǎn)品后,,我們就可大大提高我們的生產(chǎn)效率,。 54. 當(dāng)創(chuàng)建模板時(shí),留心那些帶類型的代碼并把它們放在非模板的基類中,,以防不必要的代碼膨脹,。用繼承或組合,,我們可以產(chǎn)生自己的模板,,模板中包含的大量代碼都應(yīng)是必要的,類型相關(guān)的,。 55. 不要用<cstdio>函數(shù),,例如printf()。學(xué)會(huì)用輸入輸出流來代替,,他們是安全和可擴(kuò)展類型,,而且功能也更強(qiáng)。我們?cè)谶@上面花費(fèi)的時(shí)間肯定不會(huì)白費(fèi),。一般情況下都要盡可能用C++中的庫(kù)而不要用C庫(kù),。 56. 不要用C的內(nèi)部數(shù)據(jù)類型,雖然C++為了向后兼容仍然支持他們,,但他們不像C++的類那樣強(qiáng)壯,,所以這會(huì)增加我們查找錯(cuò)誤的時(shí)間。 57. 無論何時(shí),,如果我們用一個(gè)內(nèi)部數(shù)據(jù)類型作為一個(gè)全局或自動(dòng)變量,,在我們可以初始化他們之前不要定義他們,。每一行定義一個(gè)變量,并同時(shí)對(duì)它初始化,。當(dāng)定義指針時(shí),,把"*"緊靠在類型的名字一邊。如果我們每個(gè)變量占一行,,我們就可以很安全地定義他們,。 58. 保證在所有代碼前面初始化。在構(gòu)造函數(shù)初始化表中完成所有成員的初始化,,甚至包括內(nèi)部數(shù)據(jù)類型(也是使用偽構(gòu)造函數(shù)),。在初始化子對(duì)象時(shí)用構(gòu)造函數(shù)初始化表常常更有效;否則調(diào)用了默認(rèn)構(gòu)造函數(shù),,而不再調(diào)用使初始化正確的其他成員函數(shù)(如:operator=),。 59. 不要用“MyType a = b”的形式來定義一個(gè)對(duì)象。這是常常引起混亂的原因,。因?yàn)樗{(diào)用構(gòu)造函數(shù)來代替operator=,。為了清除起見,可以用“MyType a(b)”來代替,。這個(gè)語(yǔ)句結(jié)果是一樣的,,但不會(huì)引起混亂。(雖然,,這兩種都是調(diào)用拷貝構(gòu)造函數(shù)來完成新建對(duì)象的) 60. 使用C++顯示類型轉(zhuǎn)換,。類型轉(zhuǎn)換重載了正常的類型系統(tǒng),它往往是潛在的錯(cuò)誤點(diǎn),。通過把C中一個(gè)類型轉(zhuǎn)換負(fù)責(zé)一切的情況改為多種表達(dá)清楚的轉(zhuǎn)換,,任何人來調(diào)試和維護(hù)這些代碼時(shí),都可以很容易發(fā)現(xiàn)這些最容易發(fā)生邏輯錯(cuò)誤的地方,。 61. 為了使一個(gè)程序更健壯,,每個(gè)組件都必須是很強(qiáng)壯的。在我們創(chuàng)建的類中運(yùn)用C++中提供的所有工具:隱藏實(shí)現(xiàn),、異常,、常量更正(避免用預(yù)處理器,用常量代替值),、類型檢查等等,。用這些方法我們可以再構(gòu)造系統(tǒng)時(shí)安全地轉(zhuǎn)移到下一個(gè)抽象層次。 62. 建立常量更正,。這允許編譯器指出一些非常細(xì)微且難以發(fā)現(xiàn)的錯(cuò)誤,。這需要一定訓(xùn)練,而且要在類中協(xié)調(diào)使用,,但這是完全值得的,。 63. 充分利用編譯器的錯(cuò)誤檢查功能,,用完全警告方式編譯我們的全部代碼,修改我們代碼,,直到消除所有的警告為止,。在我們的代碼中寧可犯編譯錯(cuò)誤也不要犯運(yùn)行錯(cuò)誤(比如不要用變參數(shù)列表,這會(huì)使所有類型檢查無效),。用assert來調(diào)試,,對(duì)運(yùn)行時(shí)錯(cuò)誤要進(jìn)行異常處理。 64. 寧可犯編譯錯(cuò)誤也不要犯運(yùn)行錯(cuò)誤,。處理錯(cuò)誤的代碼離出錯(cuò)點(diǎn)越近越好,。盡量就地處理錯(cuò)誤而不要拋出異常。用最近的異常處理器處理所有的異常,,這里它有足夠的信息處理它們,。在當(dāng)前層次上處理我們能解決的異常,如果解決不了,,重新拋出這個(gè)異常,。 65. 如果一個(gè)析構(gòu)函數(shù)調(diào)用了任何函數(shù),這些函數(shù)都可能拋出異常,。一個(gè)析構(gòu)函數(shù)不能拋出異常(這會(huì)導(dǎo)致terminate()調(diào)用,,它指出一個(gè)程序設(shè)計(jì)錯(cuò)誤)。所以,,任何調(diào)用了其他函數(shù)的析構(gòu)函數(shù)都應(yīng)該捕獲和管理它自己的異常,。 66. 不要自己創(chuàng)建私有數(shù)據(jù)成員名字“修飾”,除非我們有許多已在的全局值,,否則讓類和名字空間來為我們做這些事,。 67. 注意重載,一個(gè)函數(shù)不應(yīng)該用某一個(gè)參數(shù)的值來決定執(zhí)行哪段代碼,,如果遇到這種情況,,應(yīng)該產(chǎn)生兩個(gè)或多個(gè)重載函數(shù)來代替,。 68. 把指針隱藏在容器中,。只有當(dāng)我們要對(duì)它們執(zhí)行一個(gè)立即可以完成的操作時(shí)才把他們帶出來。指針已成為出錯(cuò)的一大來源,,當(dāng)用new運(yùn)算符時(shí),,應(yīng)該試著把結(jié)果指針放在一個(gè)容器中。讓容器擁有它的指針,,這樣它就會(huì)負(fù)責(zé)清楚它們,。更好的辦法是把指針打包進(jìn)來類中。如果我們?nèi)韵胱屗雌饋硐胍粋€(gè)指針,,就重載operator->和operator*,,如果我們必須有一個(gè)游離狀態(tài)的指針,,記住初始化它,最好是指向一個(gè)對(duì)象的地址,,必要時(shí)讓它等于0,。當(dāng)我們刪除它時(shí)把它置為0,以防意外的多次刪除,。 69. 不要重載全局new和delete,,可以在類的基礎(chǔ)上去重載它們。重載全局new和delete會(huì)影響整個(gè)客戶程序員的項(xiàng)目,,有些事只能由項(xiàng)目的創(chuàng)建者來控制,。檔位類重載new和delete時(shí),不要假定我們知道對(duì)象的大小,,有些人可能是從我們的類中繼承的,。用提供的參數(shù)的方法。如果我們做任何特殊的事,,要考慮到他可能對(duì)繼承者產(chǎn)生的影響,。 70. 防止對(duì)象切片。實(shí)際上以值向上類型轉(zhuǎn)換到一個(gè)對(duì)象毫無意義,。為了防止這樣,,在我們的基類中放入一些純虛函數(shù)。 71,、如果我們用異常說明,,用set_unexpected()函數(shù)安裝我們自己的unexpected()函數(shù)。我們的unexpected()應(yīng)該記錄這個(gè)錯(cuò)誤并重新拋出當(dāng)前這個(gè)異常,。這樣的話,,如果一個(gè)已存在的函數(shù)被重寫并且開始引起異常時(shí),我們可以獲得記錄,,從而修改調(diào)用代碼處理異常,。 72、建立一個(gè)用戶定義的terminate()函數(shù)(指出一個(gè)程序員的錯(cuò)誤)來記錄引起異常的錯(cuò)誤,,然后釋放系統(tǒng)資源,,并退出程序。 73,、有時(shí)簡(jiǎn)單的集中會(huì)很管用,。一個(gè)航空公司的“旅客舒適系統(tǒng)”有一系列相互五官的因素組成:座位、空調(diào),、電視等,,而我們需要在一家飛機(jī)上創(chuàng)建許多這樣的東西。我們要?jiǎng)?chuàng)建私有成員并建立一個(gè)全部的接口嗎,?不,,在這種情況下組建本身也是公開接口的一部分,,所以我們應(yīng)該創(chuàng)建公共成員對(duì)象。這些對(duì)象有它們自己的私有實(shí)現(xiàn),,所以,,也是很安全的。注意簡(jiǎn)單的集合不是常用的方法,,但也會(huì)用到,。 |
|