麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

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

effect經(jīng)典總結(jié)

2019-11-14 08:50:24
字體:
供稿:網(wǎng)友

1,C++屬于一個(gè)語言聯(lián)邦 : C     Object-Oriented C++     Template C++       STL

2,應(yīng)盡量以const,enum,inline替換#define

  如果一個(gè)常量是class專屬常量又是static,且為整數(shù)類型(int,char,bool),則需特殊處理:只要不取它們的地址,可以聲明并使用它們而不須提供定義式。

但是如果取某個(gè)class專屬常量的地址,或縱使不取其地址而編譯器卻(不正確的)堅(jiān)持要看到一個(gè)定義式,必須提供定義式

enum的行為某方面比較像#define而不像const:取一個(gè)const地址合法,但是取一個(gè)enum地址就不合法,而取#define也不合法,如果不想讓被人獲得一個(gè)pointer或reference指向你的某個(gè)整數(shù)常量,enum可以幫助你實(shí)現(xiàn)這個(gè)約束

#define和enum不會(huì)設(shè)定額外的空間,const在優(yōu)秀的編譯器中也許可能也是這樣,但是不夠優(yōu)秀的編譯器就必須設(shè)定額外的空間

3,盡可能使用const

const語法雖然變化多端,但并不莫測(cè)高深。如果關(guān)鍵字const出現(xiàn)在*左側(cè),表示被指物是常量;如果出現(xiàn)在*右邊,表示指針自身是常量;如果出現(xiàn)在*兩邊,表示被指物和指針都是常量

std::vector<int>  vec;

const std::vector<int>::interator  iter = vec.begin()                    T*const

std::vector<int>:const_iterator iter = vec.begin()                       const T*

 

將const實(shí)施于成員函數(shù)的目的,是為了確認(rèn)該成員函數(shù)可作用于const對(duì)象身上

const特性的兩個(gè)函數(shù)可以重載(必須在類中,不在類中會(huì)出現(xiàn)問題) const函數(shù)不可改變對(duì)象任何變量(注意區(qū)分指針的情況,只要指針不變,指向的值可變化)

注意操作符[]的重載要返回值的引用,否則不能對(duì)結(jié)果賦值(相當(dāng)于對(duì)值的一個(gè)拷貝賦值,沒有意義)

mutable可以在常函數(shù)中修改其值,但是一般作用是:1,用于緩存2,或必須在常函數(shù)中修改值

 

利用const Operator[]實(shí)現(xiàn)出non-const版本:

class TextBlock {

public:

           const char & operator[](std::size_t position) const {  .....               return text[position]; }

           char & operator[](std::size_t position){

                  return  const_cast<char &>(  static_cast<const  TextBlock&> (*this)[position]);

};

 

非const調(diào)用const是安全的

const調(diào)用非const是不安全的,(因?yàn)榉莄onst有可能改變)

總結(jié):

      1>將某些東西聲明為const可幫助編譯器偵測(cè)出錯(cuò)誤用法。const可被施加于任何作用域內(nèi)的對(duì)象、函數(shù)參數(shù)、函數(shù)返回類型、成員函數(shù)本體

      2>編譯器強(qiáng)制實(shí)施bitwise constness,但你編寫程序時(shí)應(yīng)該使用“概念上的常量性”(conceptual constness)

      3>當(dāng)const和non-const成員函數(shù)有著實(shí)質(zhì)等價(jià)的實(shí)現(xiàn)時(shí),令non-const版本調(diào)用const版本可避免代碼重復(fù)

4,確定對(duì)象被使用之前已被初始化:

為了保證一定性,使用內(nèi)建數(shù)據(jù)類型一定要初始化,構(gòu)造對(duì)象要保證構(gòu)造函數(shù)初始化它的成員

C++ 對(duì)“定義在不同的編譯單元內(nèi)的non-local  static對(duì)象”的初始化相對(duì)次序并無明確定義。因?yàn)闆Q定它們初始化次序相當(dāng)困難,根本無解

最常用的形式,就是  多個(gè)編譯單元內(nèi)的non-local static對(duì)象經(jīng)由“模板隱式具體化,implicit template instantiations"形式(而后者自己可能也是經(jīng)由”模板隱式具現(xiàn)化“形成)

 

任何一種non-const static對(duì)象,不論它是local或non-local,在多線程環(huán)境下“等待某事發(fā)生”都會(huì)有麻煩。處理方法:在程序的單線程啟動(dòng)階段手工調(diào)用所有的reference-returning函數(shù),這可消除與初始化有關(guān)的“競(jìng)速形勢(shì)”

 

為了避免在對(duì)象初始化之前過早地使用它們,你需要做三件事:

第一,手工初始化內(nèi)置型non-member對(duì)象。

第二,使用成員初值列對(duì)付對(duì)象的所有成分

第三,在”初始化次序不缺定性“(這對(duì)不同編譯單元所定義的non-local static對(duì)象是一種折磨)氛圍下加強(qiáng)設(shè)計(jì)

 

總結(jié):

            1>為內(nèi)置對(duì)象進(jìn)行手工初始化,因?yàn)镃++不保證初始化它們

            2>構(gòu)造函數(shù)最好使用成員初始化列表,而不要在構(gòu)造函數(shù)體內(nèi)使用賦值操作。次序和變量聲明的順序一致

            3>為免除“跨編譯單元之初始化次序”問題,請(qǐng)以local  static對(duì)象替換non-local static對(duì)象

5,編譯器默認(rèn)提供四個(gè)public且inline函數(shù),賦值,拷貝,構(gòu)造,析構(gòu),但是它們是在需要的時(shí)候才被編譯器創(chuàng)建出來的

C++不允許讓引用改指向不同的對(duì)象

>如果打算在一個(gè)“內(nèi)含reference成員”的class內(nèi)支持賦值操作,必須自己定義copy assignment操作符

>如果某個(gè)base class將copy assignment操作符聲明為PRivate,編譯器將拒絕為其derived classes 生成copy assignment操作符

 

6,若不想使用編譯器自動(dòng)生成的函數(shù),就該明確拒絕:將他們聲明為private,同時(shí)不要實(shí)現(xiàn)他們,這樣的話即使friend或者成員函數(shù)調(diào)用他們連接器會(huì)提示錯(cuò)誤

另外一種方法是把他們聲明為private在一個(gè)單獨(dú)的類中,然后用這個(gè)類繼承它

7,為多態(tài)基類聲明virtual析構(gòu)函數(shù)

>帶有多態(tài)性質(zhì)的base classes應(yīng)該聲明一個(gè)virtual析構(gòu)函數(shù)。如果class帶有任何virtual函數(shù),他就應(yīng)該擁有一個(gè)virtual析構(gòu)函數(shù)

>classes的設(shè)計(jì)目的如果不是作為base classes使用,或不是為了具備多態(tài)性,就不該聲明virtual析構(gòu)函數(shù)

8,別讓異常逃離析構(gòu)函數(shù)

>析構(gòu)函數(shù)絕對(duì)不要吐出異常。如果一個(gè)被析構(gòu)函數(shù)調(diào)用的函數(shù)可能拋出異常,析構(gòu)函數(shù)應(yīng)該捕捉任何異常,然后吞下它們(不傳播)或結(jié)束程序

>如果客戶需要對(duì)某個(gè)操作函數(shù)運(yùn)行期間拋出異常作出反應(yīng),那么class應(yīng)該提供一個(gè)普通函數(shù)(而非在析構(gòu)函數(shù)中)執(zhí)行該操作

9,絕不在構(gòu)造和析構(gòu)過程中調(diào)用virtual函數(shù)

>無法使用virtual函數(shù)從base classes向下調(diào)用,在構(gòu)造期間,可以藉由“令derived classes將必要的構(gòu)造信息向上傳遞到base class構(gòu)造函數(shù)”替換加以彌補(bǔ)

>在構(gòu)造和析構(gòu)期間不要調(diào)用virtual函數(shù),因?yàn)檫@類調(diào)用從不下降至derived class(比起當(dāng)前執(zhí)行構(gòu)造函數(shù)和析構(gòu)函數(shù)的那層)

10,令operator=返回一個(gè) reference to *this

                                                  目的是:為了實(shí)現(xiàn)“連鎖賦值”

11,在operator=中處理“自我賦值”

自我賦值     發(fā)生在對(duì)象被賦值給自己時(shí)

>確保當(dāng)對(duì)象自我賦值時(shí)operator=有良好行為。其中技術(shù)包括比較“來源對(duì)象”和“目標(biāo)對(duì)象”的地址、精心周到的語句順序、以及copy-and-swap

>確定任何函數(shù)如果操作一個(gè)以上的對(duì)象,而其中多個(gè)對(duì)象是同一對(duì)象時(shí),其行為仍然正確

12,復(fù)制對(duì)象時(shí)勿忘其每一個(gè)成分

自己編寫copying函數(shù),要確保:

1,復(fù)制所有l(wèi)ocal成員變量

2,調(diào)用所有base classes內(nèi)的適當(dāng)copying函數(shù)

 

>Copying函數(shù)應(yīng)該確保復(fù)制“對(duì)象內(nèi)的所有成員變量”及“所有base class成分”

>不要嘗試以某個(gè)copying函數(shù)實(shí)現(xiàn)另一個(gè)copying函數(shù)。應(yīng)該將共同機(jī)能放進(jìn)第三個(gè)函數(shù)中,并由兩個(gè)copying函數(shù)共同調(diào)用

 

所謂資源就是:一旦用了它,將來必須還給系統(tǒng),否則會(huì)出現(xiàn)問題。C++最常用的資源就是動(dòng)態(tài)內(nèi)存分配,當(dāng)然還有其他資源:文件描述扶,互斥鎖,圖形界面中的字型和筆刷數(shù)據(jù)庫(kù)連接、以及網(wǎng)絡(luò)sockets

13,以對(duì)象管理資源

兩個(gè)關(guān)鍵想法:

>獲得資源后立刻放進(jìn)管理對(duì)象內(nèi)

>管理對(duì)象運(yùn)用析構(gòu)函數(shù)確保資源被釋放

 

由于auto_ptr被銷毀時(shí)會(huì)自動(dòng)刪除它所指之物,所以一定要注意別讓多個(gè)auto_ptr同時(shí)指向同一對(duì)象。如果真是那樣,對(duì)象會(huì)被刪除一次以上,而那會(huì)使你的程序搭上駛向“未定義行為”的快速列車上。為了預(yù)防這個(gè)問題,auto_ptr有一個(gè)不尋常的性質(zhì):若通過copy構(gòu)造函數(shù)或copy assignment操作符復(fù)制它們,它們會(huì)變成null,而復(fù)制所得的指針將取的資源的唯一控制權(quán)!!!(該性質(zhì)有利也有弊)

 

auto_ptr的替代方案是“引用計(jì)數(shù)型智慧指針”(RCSP),RCSP也是個(gè)智能指針,持續(xù)追蹤共有多少對(duì)象指向某筆資源,并在無人指向它時(shí)自動(dòng)刪除該資源。RCSP提供的行為類似垃圾回收,不同的是RCSP無法打破環(huán)狀引用:::tr1:shared_ptr就是一個(gè)RCSP

 

注意:auto_ptr和tr1::shared_ptr兩者都在析構(gòu)函數(shù)內(nèi)做delete而不是delete[]動(dòng)作!!如果對(duì)數(shù)組指針調(diào)用則是餿主意

 

>為了防止資源泄漏,請(qǐng)使用RAII對(duì)象,它們?cè)跇?gòu)造函數(shù)中活得資源并在析構(gòu)函數(shù)中釋放資源 (Resource Acquisition Is Initialization,RAII)

>兩個(gè)常被使用的RAII  classes分別是tr1::shared_ptr和auto_ptr。前者通常是較佳選擇,已經(jīng)其copy行為比較直觀。若選擇auto_ptr,復(fù)制動(dòng)作會(huì)時(shí)它(被復(fù)制物)指向null

14,在資源管理類中小心copying行為

在RAII中當(dāng)一個(gè)對(duì)象被復(fù)制時(shí),出現(xiàn)嚴(yán)重后果,一般有兩種方案:

>禁止復(fù)制(聲明為private)

>對(duì)底層資源祭出“引用計(jì)數(shù)法”(reference-count)           這種做法一般如果內(nèi)含有一個(gè)tr1::shared_ptr ,但是默認(rèn)事件是count為0時(shí)刪除,幸運(yùn)的是我們可以自己指定為0時(shí)的事件

 

類的析構(gòu)函數(shù)會(huì)自動(dòng)調(diào)用其non-static成員變量的析構(gòu)函數(shù)

復(fù)制底部資源                             (深度拷貝)

轉(zhuǎn)移底部資源的擁有權(quán)              (auto_ptr)

 

15,在資源管理類中提供對(duì)原始資源的訪問

tr1::shared_ptr和auto_ptr都提供了一個(gè)get函數(shù),用來執(zhí)行顯式轉(zhuǎn)換,也就是它返回智能指針內(nèi)部的原始指針,以便于直接訪問時(shí)可以通過

它們還重載了(->和*)操作符

 

>APIs往往要求訪問原始資源(raw resources),所以每一個(gè)RAII class應(yīng)該提供一個(gè)“取得其所管理之資源”的辦法

>對(duì)原始資源的訪問可能經(jīng)由顯式轉(zhuǎn)換或隱式轉(zhuǎn)換。一般而言顯式轉(zhuǎn)換比較安全,但隱式轉(zhuǎn)換對(duì)客戶比較方便

 

16,成對(duì)使用new和delete時(shí)要采用相同形式

           最好不要用typedef,否則會(huì)造成語義不清:

         typedef  std::string AddressLines[4];

         std::string  *pal = new AddressLines;

         delete pal;          錯(cuò)誤!!!

         delete[] pal ;       正確!!!

17,以獨(dú)立語句將newed對(duì)象置入智能指針

>      以獨(dú)立語句將newed對(duì)象存儲(chǔ)于(置入)智能指針內(nèi)。如果不這樣做,一旦異常被拋出,有可能導(dǎo)致難以覺察的資源泄露

 

18,讓接口容易被正確使用,不易被誤用

>好的接口很容易被正確的使用,不容易被誤用。應(yīng)該在所有的接口中努力達(dá)成這些性質(zhì)

>“促進(jìn)正確使用”的辦法包括接口一致性,以及與內(nèi)置類型的行為兼容

>“組織誤用”的辦法包括建立新類型、限制類型上的操作,束縛對(duì)象值,以及消除客戶的資源管理責(zé)任

>tr1::shared_ptr支持定制型刪除器。這個(gè)防范DLL問題,可被用來自動(dòng)解除互斥鎖等等

 

19,設(shè)計(jì)class猶如設(shè)計(jì)type

好的types是一項(xiàng)艱巨的工作。好的types有自然的語法,直觀的語義,以及一或多個(gè)高效的實(shí)現(xiàn)品

如何設(shè)計(jì)好的classes:

>新的type的對(duì)象應(yīng)該如何被創(chuàng)建和銷毀

>對(duì)象的初始化和對(duì)象的賦值該有什么差別

>新的type的對(duì)象如果被passed by value(以值傳遞),意味著什么

>什么是新type的“合法值”

>新的type需要配合某個(gè)繼承圖系么

>新的type需要什么樣的轉(zhuǎn)換

>什么樣的操作符和函數(shù)對(duì)此新type而言是合理的

>什么樣的標(biāo)準(zhǔn)函數(shù)應(yīng)該駁回

>誰該取用新type的成員

>什么是新type的“未聲明接口”

>新type有多么一般化

>真的需要一個(gè)新type么

 

20,寧以pass-by-reference-to-const替換pass-by-value

>盡量以pass-by-reference-to-const替換pass-by-value。前者通常比較高效,并可避免切割問題

>以上規(guī)則并不適用于內(nèi)置類型,以及STL的迭代器和函數(shù)對(duì)象。對(duì)它們而言,pass-by-value往往比較適當(dāng)

 

21,必須返回對(duì)象時(shí),別妄想返回其reference

任何時(shí)候看到一個(gè)reference聲明式,都應(yīng)該立刻問自己,它的另一個(gè)名稱是什么?因?yàn)樗欢ㄊ悄澄锏牧硪粋€(gè)名稱

任何函數(shù)如果返回一個(gè)reference指向某個(gè)local對(duì)象,都將一敗糊涂

>絕不要返回point或reference指向一個(gè)local stack對(duì)象,或返回reference指向一個(gè)heap-allocated對(duì)象,或返回pointer或reference指向一個(gè)local static對(duì)象而有可能同時(shí)需要多個(gè)這樣的對(duì)象

 

22,將成員變量聲明為private

>切記將成員函數(shù)聲明為private。這可賦予客戶訪問數(shù)據(jù)的一致性、可細(xì)微劃分訪問控制、允許約束條件獲得保證,并提供class作者以充分的實(shí)現(xiàn)彈性

>protected并不比public更具封裝性

 

23,寧以non-menber、non-friend替換menber函數(shù)

這樣做可以增加封裝性、包裹彈性和機(jī)能擴(kuò)充性

 

24,若所有參數(shù)皆需要類型轉(zhuǎn)換,請(qǐng)為此采用non-member函數(shù)

>如果需要為某個(gè)函數(shù)的所有參數(shù)(包括被this指針?biāo)傅哪莻€(gè)隱喻參數(shù))進(jìn)行類型轉(zhuǎn)換,那么這個(gè)函數(shù)必須是個(gè)non-member

 

25,考慮一個(gè)不拋出異常的swap函數(shù)

 pimpl手法    :point to implementation

C++只允許對(duì)class template偏特化,在function templates身上偏特化行不通,解決方案是:為它添加一個(gè)重載版本

>當(dāng)std::swap對(duì)你的類型效率不高時(shí),提供一個(gè)swap成員函數(shù),并確定 這個(gè)函數(shù)不拋出異常

>如果你提供一個(gè)member swap,也該提供一個(gè)non-member swap用來調(diào)用前者。對(duì)于classes(而非templates),也請(qǐng)?zhí)鼗痵td::swap

>調(diào)用swap時(shí)應(yīng)針對(duì)std::swap使用using聲明式,然后調(diào)用swap并且不帶任何“命名空間資格修飾”

>為“用戶定義類型”進(jìn)行std  template全特化是好的,但千萬不要嘗試在std內(nèi)加入某些對(duì)std而言全新的東西

 

26,盡可能延后變量定義式的出現(xiàn)時(shí)間

 >盡可能延后變量定義式的出現(xiàn)。這樣做可增加程序的清晰度并改善程序的效率。

 

27,盡量少做轉(zhuǎn)型動(dòng)作

>const_cast通常被用來將對(duì)象的常量性轉(zhuǎn)除。它也是唯一有此能力的C++-style轉(zhuǎn)型操作符

>dynamic_cast主要用來執(zhí)行“安全向下轉(zhuǎn)型”,也就是用來決定某對(duì)象是否歸屬繼承體系中的某個(gè)對(duì)象。它是唯一無法由舊式語法執(zhí)行的動(dòng)作,也是唯一可能耗費(fèi)重大運(yùn)行成本的轉(zhuǎn)型動(dòng)作

>reinterpret_cast意圖執(zhí)行低級(jí)轉(zhuǎn)型,實(shí)際動(dòng)作(及結(jié)果)可能取決于編譯器,這也就是表示它不可移植。例如將point to int轉(zhuǎn)型為int

>static_cast用來強(qiáng)迫飲食轉(zhuǎn)換。例如將non-const轉(zhuǎn)型const對(duì)象,或?qū)nt轉(zhuǎn)型double等等。但是無法將const轉(zhuǎn)型non-const

 

任何一個(gè)類型轉(zhuǎn)換(不論是通過轉(zhuǎn)型操作而進(jìn)行的顯式轉(zhuǎn)換,或通過編譯器完成的隱式轉(zhuǎn)換)往往真的令編譯器編譯出運(yùn)行期執(zhí)行的碼

 

單一對(duì)象(例如Derived對(duì)象)可能擁有一個(gè)以上的地址(例如“以base *指向它”時(shí)的地址和“以Derived *指向它”時(shí)的地址)行為

之所以需要dynamic_cast,通常是因?yàn)橄朐谝粋€(gè)認(rèn)定為derived對(duì)象身上執(zhí)行derived class操作函數(shù),但手上卻只有一個(gè)"指向base”的pointer或reference,只能靠它們呢來處理對(duì)象

絕對(duì)必須避免的一件事是所謂的"連串 dynamic_casts"

 

>如果可以,盡量避免轉(zhuǎn)型,特別是在注重效率的代碼中避免dynamic_casts。如果有個(gè)設(shè)計(jì)需要轉(zhuǎn)型這個(gè)動(dòng)作,試著發(fā)展無需轉(zhuǎn)型的替代品

>如果轉(zhuǎn)型是必要的,試著將它隱藏于某個(gè)函數(shù)背后。客戶隨后可以調(diào)用該函數(shù),而不需要將轉(zhuǎn)型放進(jìn)他們自己的代碼內(nèi)

>寧可使用C++-style轉(zhuǎn)型,不要使用舊式轉(zhuǎn)型。前者容易辨識(shí)出來,而且也比較有著分門別類的職掌

 

28,避免返回handles指向?qū)ο髢?nèi)部成分

 兩個(gè)教訓(xùn):

          --->成員變量的封裝性最多只等于"返回其reference"的函數(shù)的訪問級(jí)別

          --->如果const成員函數(shù)傳出一個(gè)reference,后者所指數(shù)據(jù)與對(duì)象自身關(guān)聯(lián),而它又被存儲(chǔ)于對(duì)象之外,那么這個(gè)函數(shù)的調(diào)用者可以修改那筆數(shù)據(jù)

handles: 指針,reference,迭代器

避免返回handles(reference,pointer,iterator)指向?qū)ο髢?nèi)部。遵守這個(gè)約定可增加封裝性,幫助const成員函數(shù)的行為像個(gè)const,并將發(fā)生”虛吊號(hào)碼牌“(dangling handles)的可能性降到最低

 

29,為"異常安全"而努力是值得的

當(dāng)異常被拋出時(shí),帶有異常安全性的函數(shù)會(huì):

=>不泄露任何資源

=>不允許數(shù)據(jù)敗壞

 

異常安全函數(shù)提供以下三個(gè)保證之一:

==>基本承諾

==>強(qiáng)烈保證

==>不拋擲保證

1,> 異常安全函數(shù)(Exception-safe functions)即使發(fā)生異常也不會(huì)泄露資源或允許任何數(shù)據(jù)結(jié)構(gòu)敗壞。這樣的函數(shù)區(qū)分三種可能的保證:基本型,強(qiáng)烈型,不拋異常型

2,>“強(qiáng)烈保證"往往能夠以copy-and-swap實(shí)現(xiàn)出來,但"強(qiáng)烈保證"并非對(duì)所有函數(shù)都可實(shí)現(xiàn)或具備實(shí)現(xiàn)意義

3,>函數(shù)提供的"異常安全保證"通常最高只等于其所調(diào)用之各個(gè)函數(shù)的"異常安全保證"中的最弱者

30,透徹了解inlining的里里外外

inline只是對(duì)編譯器的一個(gè)申請(qǐng),不是強(qiáng)制命令

inline函數(shù)通常 一定 被置于頭文件內(nèi)

inline 在大多數(shù)C++程序中時(shí)編譯器行為,只有少數(shù)基于.NET CLI(Common Language Infrastructure,公共語言基礎(chǔ)設(shè)施)可以在運(yùn)行期完成inlining

Template通常也被置于頭文件中,以為一旦被使用,編譯器為了將它具現(xiàn)化,需要知道它長(zhǎng)什么樣子(像inline),(并不是同一準(zhǔn)則,某些建置環(huán)境可以在連接期執(zhí)行template具現(xiàn)化)

編譯器拒絕將過于復(fù)雜的函數(shù)(循環(huán)或遞歸)的函數(shù)inlining。而所有對(duì)virtual函數(shù)的調(diào)用(除非最平淡無奇的)也對(duì)會(huì)使inling落空,因?yàn)関irtual是運(yùn)行期確定

編譯器通常不對(duì)“通過函數(shù)指針而進(jìn)行的調(diào)用”實(shí)施inlining,因?yàn)橐_定地址

inline函數(shù)無法升級(jí)

很多調(diào)試器對(duì)inline函數(shù)束手無策

 

>將大多數(shù)inlining限制在小型、被頻繁調(diào)用的函數(shù)身上。這可使日后的調(diào)試過程和二進(jìn)制升級(jí)更容易,也可使?jié)撛诘拇a膨脹問題最小化,使程序的速度提升機(jī)會(huì)最大化

>不要只因?yàn)閒unction templates出現(xiàn)在頭文件,就將它們聲明為inline

 

31,將文件間的編譯依存關(guān)系降至最低

如果使用object references 或 object pointers可以完成任務(wù),就不要使用objects

如果能夠,盡量以class聲明替換class定義式

為聲明式和定義式提供不同的頭文件

>支持“編譯依存性最小化”的一般構(gòu)想是:相依于聲明式,不要 相依于定義式。基于此構(gòu)想的兩個(gè)手段是Handle classes和Interface classes

>程序庫(kù)頭文件應(yīng)該以“完全且僅有聲明式”的形式存在。這種做法不論是否涉及templates都適用

 

繼承與面向?qū)ο?/p>

 

32,確定public繼承塑模出is-a關(guān)系

以C++進(jìn)行面向?qū)ο缶幊蹋钜囊粋€(gè)原則:公開繼承 意味 "is-a“的關(guān)系

企鵝是一種鳥,但企鵝不會(huì)飛 理論解決辦法:1,雙繼承  2,重新(一個(gè)錯(cuò)誤的)飛功能  3,都不寫飛功能

 

>"public"繼承意味著is-a。適用于base classes身上的每一件事情一定也適用于derived classes身上,因?yàn)槊恳粋€(gè)derived class對(duì)象也都是一個(gè)

base class對(duì)象

 

33,避免遮掩繼承而來的名稱

 

復(fù)制代碼
 1 #include <iostream> 2 using namespace std; 3  4 class Base { 5 private: 6     int x; 7 public: 8     virtual void mf1() = 0; 9     virtual void mf1(int);10     virtual void mf2();11     void mf3();12     void mf3(double);13 };14 15 class Derived : public Base {16 public:17     virtual void mf1();18     void mf3();19     void mf4();20 };21 22 int main()23 {24     Derived d;25     int x;26 27     d.mf1();   //Derived::mf128     d.mf1(x);  //ERROR !!!  NO ARGS              using Base::mf129     d.mf2();   //Base::mf230     d.mf3();   //Derived::mf331     d.mf3(x);  //ERROR !!! NO ARGS               using Base::mf332 33     return 0;34 }復(fù)制代碼

 

 

 

 上面的程序只是為了說明編譯時(shí)候的正確性,因此有些函數(shù)沒有實(shí)現(xiàn),鏈接肯定通不過,不過能說明問題

 

>derived classes內(nèi)的名稱會(huì)遮掩base classes內(nèi)的名稱。在public繼承下從來沒有人希望如此

>為了讓被遮掩的名稱再見天日,可使用using聲明式或轉(zhuǎn)交函數(shù)

 

34,區(qū)分接口繼承和實(shí)現(xiàn)繼承

 聲明一個(gè)pure virtual函數(shù)的目的是為了讓derived classes只繼承函數(shù)接口

 聲明簡(jiǎn)樸的(非純)impure virtual函數(shù)的目的,是讓derived classes繼承該函數(shù)的接口和缺省實(shí)現(xiàn)

 聲明non-virtual函數(shù)的目的是為了令derived classes繼承函數(shù)的接口及一份強(qiáng)制性實(shí)現(xiàn)

 一個(gè)典型的程序有80%的執(zhí)行時(shí)間花費(fèi)在%20的代碼身上

>接口繼承和實(shí)現(xiàn)繼承不同。在public繼承之下,derived classes總是繼承base class的接口

>pure virtual函數(shù)只具體指定接口繼承

>簡(jiǎn)樸的(非純)impure virtual函數(shù)具體指定接口繼承及缺省實(shí)現(xiàn)繼承

 

>non-virtual函數(shù)具體指定接口繼承以及強(qiáng)制性實(shí)現(xiàn)繼承

 

35,考慮virutal 函數(shù)以外的其他選擇

>virtual函數(shù)的替代方案包括NVI手法及Stratrgy設(shè)計(jì)模式的多種形式。NVI手法自身是一個(gè)特殊形式的Template Method設(shè)計(jì)模式

>將機(jī)能從成員函數(shù)移到class外部函數(shù),帶來的一個(gè)缺點(diǎn)是,非成員函數(shù)無法訪問class的non-public成員

>tr1::function對(duì)象的行為就像一般函數(shù)指針。這樣的對(duì)象可接納“與給定值目標(biāo)簽名兼容”的所有可調(diào)用物

 

36,絕不重新定義繼承而來的non-virtual函數(shù)

>絕對(duì)不要重新定義繼承而來的non-virtual

 

37,絕不重新定義繼承而來的缺省參數(shù)值

virtual函數(shù)系動(dòng)態(tài)綁定,而缺省參數(shù)值卻是靜態(tài)綁定

>絕對(duì)不要重新定義一個(gè)繼承而來的缺省參數(shù)值,因?yàn)槿笔?shù)值都是靜態(tài)綁定,而virtual函數(shù)—你唯一應(yīng)該覆寫的東西——確實(shí)動(dòng)態(tài)綁定

 

38,通過復(fù)合塑模出has-a或“根據(jù)某物實(shí)現(xiàn)出”

>復(fù)合的意義和public繼承完全不同

>在應(yīng)用域,復(fù)合意味has-a。在實(shí)現(xiàn)域,復(fù)合意味is-implemented-in-terms-of(根據(jù)某物實(shí)現(xiàn)出)

 

39,明智而審慎的使用private繼承

private繼承主要用于“當(dāng)一個(gè)意欲成為derived class者想訪問一個(gè)意欲成為base class者的protected成分,或?yàn)榱酥匦露x一或多個(gè)virtual函數(shù)

EBO  empty base optimization 空白基類最優(yōu)化,只適用于單一繼承

復(fù)合和private繼承都意味 is-implemented-in-terms-of

>Private 繼承意味is-implemented-in-terms-of(根據(jù)某物實(shí)現(xiàn)出)。它通常比復(fù)合的級(jí)別低。但是當(dāng)derived class需要訪問protected base class的成員,或需要重新定義繼承而來的virtual函數(shù)時(shí),這么設(shè)計(jì)是合理的

>和復(fù)合不同,private繼承可以造成empty base最優(yōu)化。這對(duì)致力于“對(duì)象尺寸最小化”的程序庫(kù)開發(fā)者而言,可能很重要

 

40,明智而審慎的使用多重繼承

C++編譯器解析重載函數(shù)調(diào)用的規(guī)則:在看到是否有個(gè)函數(shù)可取用之前,C++首先確認(rèn)這個(gè)函數(shù)對(duì)此調(diào)用的最佳匹配。找出最佳匹配函數(shù)后才檢驗(yàn)其可取用性

virtual base的初始化責(zé)任是由繼承體系中的最低層class 負(fù)責(zé)。這暗示:

1>classes若派生自virtual bases而需要初始化,必須認(rèn)知其virtual bases——不論那些bases距離多遠(yuǎn)

2>當(dāng)一個(gè)新的derived class加入繼承體系中,它必須承擔(dān)起virtual bases(不論直接還是間接)的初始化責(zé)任

對(duì)待virtual base classes: 1,非必須不是有2,如果必須使用,盡可能避免在其中放置數(shù)據(jù)

 

>多重繼承比單一繼承復(fù)雜。它可能導(dǎo)致新的歧義性,以及對(duì)virtual繼承的需要

>virtual繼承會(huì)增加大小,速度,初始化(及賦值)復(fù)雜度等等成本。如果virtual base classes不帶任何數(shù)據(jù),將是最具實(shí)用價(jià)值的情況

>多重繼承的確有正當(dāng)用途。其中一個(gè)情節(jié)涉及"public繼承某個(gè)Interface class"和"private 繼承某個(gè)協(xié)助實(shí)現(xiàn)的class"的兩相組合

 

41,了解隱式接口和編譯期多態(tài)

Templates及泛型編程的世界,與面向?qū)ο笥懈镜牟煌T诖耸澜缰酗@式接口和編譯期多態(tài)依然存在,但重要性降低。反倒是隱式接口和編譯期多態(tài)移到前面了

>classes和templates都支持接口和多態(tài)

>對(duì)classes而言接口是顯式的,以函數(shù)簽名為中心。多態(tài)則是通過virtual函數(shù)發(fā)生于運(yùn)行期

>對(duì)template參數(shù)而言,接口是隱式的,奠基于有效表達(dá)式。多態(tài)則是通過template具現(xiàn)化和函數(shù)重載解析發(fā)生于編譯期

 

42,了解typename的雙重意義

template內(nèi)出現(xiàn)的名稱如果相依于某個(gè)template參數(shù),稱之為從屬名稱

如果C++解析器在template中遭遇一個(gè)嵌套從屬名稱,它便假設(shè)這個(gè)名稱不是個(gè)類型,除非告訴它是(typename)

typename不可以出現(xiàn)在base classes list內(nèi)的嵌套從屬類型名稱之前,也不可以在member initialization list中作為base class修飾符

>聲明template參數(shù)時(shí),前綴關(guān)鍵字class和typename可互換

>請(qǐng)使用關(guān)鍵字typename標(biāo)識(shí)嵌套從屬類型名稱;但不得在base class list(基類列)或member initialization list內(nèi)以它作為base class修飾符

 

43, 學(xué)習(xí)處理模板化基類內(nèi)的名稱

class 定義式最前面的"template<>"語法象征這既不是template也不是標(biāo)準(zhǔn)的class 。而是模板全特化

C++編譯期往往拒絕在templatized base classes(模板化基類)內(nèi)尋找繼承而來的名稱,因?yàn)橛锌赡芴鼗鴵碛胁煌慕涌冢】蛇@是個(gè)嚴(yán)重的問題,我們可以有三個(gè)辦法解決:

1,在調(diào)用base class函數(shù)動(dòng)作之前加上this->

2, 使用using聲明式

3, 明白指出被調(diào)用函數(shù)位于base class內(nèi),但是如果是虛函數(shù)的話會(huì)導(dǎo)致關(guān)閉虛函數(shù)"virtual 綁定行為"

 

>可在derived class tempalte內(nèi)通過"this->"指涉base class templates內(nèi)的成員名稱,或藉由一個(gè)明白的"base class資格修飾符"完成

 

44, 將于參數(shù)無關(guān)的代碼抽離templates

>Template生成多個(gè)classses和多個(gè)函數(shù),所以任何template代碼都不該與某個(gè)構(gòu)造成膨脹的template參數(shù)產(chǎn)生相依關(guān)系

>因非類型模板參數(shù)而造成的代碼膨脹,往往可消除,做法是以函數(shù)參數(shù)或class成員變量替換template參數(shù)

>因類型參數(shù)而造成的代碼膨脹,往往可降低,做法是讓帶有完全相同二進(jìn)制表述的具現(xiàn)類型共享實(shí)現(xiàn)碼

 

45,運(yùn)用成員函數(shù)模板接受所有兼容類型

>請(qǐng)使用member function templates生成"可接受所有兼容類型"的函數(shù)

>如果你聲明member templates用于"泛化copy構(gòu)造"或"飯或assignment操作",你還是需要聲明正常的copy構(gòu)造函數(shù)和copy assignment操作符

 

46, 需要類型轉(zhuǎn)換時(shí)請(qǐng)為模板定義非成員函數(shù)

在template實(shí)參推導(dǎo)過程中從不將隱式類型轉(zhuǎn)換函數(shù)納入考慮

>當(dāng)我們編寫一個(gè)class template,而它所提供之"與此template相關(guān)的"函數(shù)支持"所有參數(shù)之隱式類型轉(zhuǎn)換"時(shí),請(qǐng)將那些函數(shù)定義為"class template內(nèi)部的friend函數(shù)"

 

47, 請(qǐng)使用traits classes表現(xiàn)類型信息

>Traits classes使得"類型相關(guān)信息"在編譯期可用。它們以templates和"templates特化"完成實(shí)現(xiàn)

>整合重載技術(shù)后,traits classes有可能在編譯期對(duì)類型執(zhí)行if ... else 測(cè)試

 

48, 認(rèn)識(shí)template元編程

 

復(fù)制代碼
 1 #include <iostream> 2  3 template<unsigned n> 4 struct Factorial 5 { 6     enum { value = n * Factorial<n-1>::value}; 7 }; 8  9 template<>10 struct Factorial<0> {11     enum { value = 1 };12 };13 14 15 int main(int argc,char *argv[])16 {17     std::cout << Factorial<5>::value << std::endl;18     std::cout << Factorial<10>::value << std::endl;19 20     return 0;21 }復(fù)制代碼

 

好處:1,確保量度單位正確 2,優(yōu)化矩陣 3, 可以生成客戶定制之設(shè)計(jì)模式

 

>Template metaprograming可將工作由運(yùn)行期移往編譯期,因而得以實(shí)現(xiàn)早期錯(cuò)誤偵測(cè)和更高的執(zhí)行效率

>TMP可被用來生成"基于政策選擇組合"的客戶定制代碼,也可用來避免生成對(duì)某些特殊類型不適合的代碼

 

49,了解new-handler的行為

new-handler函數(shù)必須做以下事情:

1= 讓更多內(nèi)存可被使用

2= 安裝另一個(gè)new-handler

3= 卸除new-handler

4= 拋出bad_alloc(或派生自bad_alloc)的異常

5= 不返回

 

operator new要做以下事情:

1= 調(diào)用set_new_handler,告知Widget的錯(cuò)誤處理函數(shù)。這會(huì)將class的new-handler安裝為global new-handler

2= 調(diào)用global operator new,執(zhí)行實(shí)際之內(nèi)存分配。如果分配失敗,global operator new會(huì)調(diào)用class的new-handler,因?yàn)槟莻€(gè)函數(shù)才剛被安裝為global new-handler。如果global operator new最終無法分配足夠內(nèi)存,會(huì)拋出一個(gè)bad_alloc異常。在此情況下class的operator new必須恢復(fù)原來的global new-handler,然后再傳播該異常。為確保原來的new-handler總是能夠被重新安裝回去,class將global new-handler視為資源并遵守忠告,運(yùn)用資源管理對(duì)象防止資源泄漏

3= 如果global operator new能夠分配足夠一個(gè)class對(duì)象所用的內(nèi)存,class的operator new會(huì)返回一個(gè)指針,指向分配所得。class析構(gòu)函數(shù)會(huì)管理golbal new-handler,它會(huì)自動(dòng)將class ‘s operator new被調(diào)用前的那個(gè)global new-handler恢復(fù)回來

 

50,了解new和delete的合理替換機(jī)制

51,編寫new和delete時(shí)需固守常規(guī)

52,寫placement new 也要寫 placement delete

53,不要輕易忽略編譯期警告

54,讓自己熟悉包括TR1在內(nèi)的標(biāo)準(zhǔn)程序庫(kù)

55,讓自己熟悉Boost

有一種落差是,你配不上自己的野心,也辜負(fù)了所受的苦難
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 天天鲁在线视频免费观看 | 在线亚洲播放 | 午夜网站视频 | 成片免费观看视频大全 | 黑人一级片 | 亚洲一二区视频 | 国产一区二区在线观看视频 | 亚洲精品成人18久久久久 | 国产精品午夜性视频 | 毛片三区| 日韩精品久久久久久 | 青青青在线免费 | 国产乱淫av一区二区三区 | 福利在线免费视频 | 色视频欧美 | 激情亚洲一区二区三区 | 成人视屏在线 | 看91视频 | 久章草影院 | 久久久资源网 | 羞羞视频免费观看网站 | 免费观看黄色影片 | 国产成人精品网站 | 国产噜噜噜噜久久久久久久久 | 99精品视频在线免费观看 | 黄色大片在线观看 | 欧美亚洲国产成人 | 久久av喷吹av高潮av懂色 | 欧美一级黑人 | av在线免费观看中文字幕 | 性生活视频一级 | 免费一级毛片在线播放视频 | 色综合久久久久久久久久久 | 欧美一级毛片免费观看视频 | 黄色一级电影网 | 手机视频在线播放 | 男人的天堂色偷偷 | 日本特级a一片免费观看 | 日本人乱人乱亲乱色视频观看 | 神马久久精品综合 | 在线小视频国产 |