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

Effective C++筆記(轉)

0. 拷貝構造函數和賦值運算符

copy構造函數用來“以同型對象初始化自我對象”,copy assignment操作符被用來“從另一個同型對象中”拷貝其值到自我對象

copy構造函數使用時,自我對象并沒有被實例化;而copy assignment操作符使用時自我對象已經被實例化

如:

String str1("Hello");

String str2(str1);    
// copy constructor

String str3 
= str1;   // 注意:copy constructor !

String str4;           

str4 
= str1;            // copy assignment

1. 將構造函數聲明為explicit可以阻止它們被用來執行隱式類型轉換。

如:

有一個函數 void doSomething(B bObject);

 B有一個接受int的構造函數 B::B(int b);

B obj1(100);

doSomething(obj1);   // ok

doSomething(28);     // 如果沒聲明explicit可以,反之不行


2. 條款三:盡可能使用const. Use const  whenever possible

const實施于成員函數的目的,是為了確認該成員函數可作用于const 對象身上。它承諾絕不改變其對象的邏輯狀態。它可以使class的接口更加容易理解;而且,它們使操作const對象成為可能,因為改善c++效率的一個根本方法就是以pass by reference-to-const方式傳遞對象,而此技術的前提是我們有const成員函數可用來處理取得(并經修飾而成)的const對象

很多人都漠視的一個事實:如果兩個成員函數只是常量性(const 與否)不同,它們可以被重載。

const和指針,要小心const和指針的關系

如果一個指針*pconst對象的成員,我們不改變指針值p(也就是它指向哪個對象)而改變*p(它所指向對象的值),那么編譯器不會對此提出異議。這同樣適用于const成員函數中的情況。 

一個增加靈活性聲明:聲明為【mutable】的成員變量可能總是會被更改,即使在const成員函數內

const_cast<> 運算符可以用來轉換掉對象的const屬性

請記?。?/span>

<!--[if !supportLists]-->l         <!--[endif]-->將某些東西聲明為const可幫助編譯器偵測出錯誤用法。const可被施加于任何作用域內的對象、函數參數、函數返回值類型、成員函數本體。

<!--[if !supportLists]-->l         <!--[endif]-->編譯器強制實施bitwise constness,但你應該使用conceptual constness 適當的使用mutable和注意指針帶來的影響。

<!--[if !supportLists]-->l         <!--[endif]-->const函數和non-con函數有實質等價的實現時,可利用non-const函數調用const函數避免重復代碼。

 

3. 條款四:確定對象在使用前已初始化. Make sure that object are initialized before they’re used.

別混淆賦值(assignment)和初始化(initialization

C++規定,對象的成員變量的初始化動作發生在進入構造函數本體之前,應該使用初始化列表實現。

在構造函數本體內進行的只是賦值而不是初始化。初始化發生的事件更早,發生于這些成員的default構造函數被自動調用之時(比進入構造函數本體的時間更早)。這樣構造函數所做的一切工作都浪費了。

請立下一個規矩:總是在初始化列表中列出所有成員變量(包括內置類型),以免還得記住哪些成員變量(如果它們在初值列中被遺漏的話)可以無需初值。

當然,你可以將那些“賦值表現像初始化一樣好”的成員變量,改用賦值操作并移入一個private函數,在所有的構造函數中調用它,以避免不必要的編碼重復。這種做法在成員變量的初值系“由文件或數據庫”讀入時特別有用。

C++有著十分固定的“成員初始順序”。Base早于derived,成員變量按聲明順序。

對于non-local static對象,使用singleton是個不錯的方案

請記住

<!--[if !supportLists]-->l         <!--[endif]-->為內置型對象進行手工初始化,C++不保證初始化他們

<!--[if !supportLists]-->l         <!--[endif]-->構造函數最好使用成員初始化列表,而不要在構造函數本體內賦值。其排列次序應按照聲明次序

<!--[if !supportLists]-->l         <!--[endif]-->Singleton實現non-local static對象


4. 條款05 了解C++默默編寫并調用哪些函數. Know what functions C++ silently writes and calls.

為了駁回編譯器自動提供的功能(默認構造函數、默認析構函數、默認拷貝構造函數、默認賦值操作符),可將相應的成員函數聲明為private并且不予實現。

將構造函數聲明為explicit可以阻止隱式類型轉換.


5. 條款07:為多態基類聲明virtual 析構函數. Declare destruction vritual in polymorphic base class.

C++ 明確指出:當derived class對象經由一個base class指針被刪除,而該base class帶有一個non-virtual析構函數,其結果是未定義——實際執行時通常發生的事對象的derived成分沒被銷毀。

消除這個問題的辦法很簡單,base class聲明一個virtual析構函數。

任何函數只要帶有一個virtual函數幾乎確定也應該有一個virtual析構函數。

如果class不含virtual函數,通常表示它并不意圖被用作一個base class。

無端地將所有class的析構函數都聲明為virtual就像從未聲明它們為virtual一樣,都是錯誤的。很多人的心的事:只有當class內含有至少一個virtual函數才將它聲明為virtual析構函數。

base class的析構函數聲明為純虛函數是定義抽象類的常用手法,但是這個純虛析構函數仍需提供定義,因為derived class需要調用base class的析構函數。如果未定義則會導致鏈接錯誤。

 

6. 條款12:Copy all parts of an object. 復制對象時勿忘其每一個成分

derived class 應在拷貝構造函數的初始化列表和賦值運算符的函數體內調用base class的拷貝構造函數和賦值運算符。否則將導致初始化不完整。

class Customer /* … */ };

class PriorityCustomer : public Customer /* .. */}

PriorityCustomer::PriorityCustomer(PriorityCustomer 
&rhs) : Customer(rhs) {
    // 調用base class Customer拷貝構造函數

       
/*

       …

       
*/


}


PriortiyCustomer
& PriorityCustomer::operator=(PriorityCustomer &rhs){

       Customer::
operator=(rhs);   // 調用base class operator=

 

       
/*

       …..

       
*/


      return *this;

}



7. 條款13:以對象管理資源. Use objects to manager resources.

善于使用智能指針,為了防止資源泄漏,請使用RAII對象,他們在構造函數中獲得資源并在析構函數中釋放資源。

兩個常用的RAII classestr1::shared_ptrauto_ptr。前者往往是較佳選擇(通過引用計數器實現),后者不支持指針的拷貝和復制,復制動作會使它(被復制物)指向null。

類似的Boost庫中的boost::scoped_arrayboost::shared_array類也可以提供類似功能

void test_fun()
{

     std::auto_ptr
<Child> aptr_c(new Child("Child 1"));

     Child 
*ptr = new Child("Child 2");

     aptr_c.
get()->func();                  // 盡量使用顯示轉換,防止不合適的隱式轉換

     (
*aptr_c).func();                      // 使用隱式轉換,可以增強可讀性
 

     std::auto_ptr
<Child> aptr_c2 = aptr_c;  // will set aptr_c to null

     
// aptr_c->func();                      failed. aptr_c is null.

     delete ptr;
}


智能指針auto_ptr可以在生命期結束時自動銷毀返回資源。盡量使用智能指針保存factory函數返回的指針。

此外,利用棧對象自動銷毀調用析構函數的特性,可以將需要釋放的資源根據作用域封裝在棧對象中,此棧對象即為一個資源管理對象,對應類為資源管理類。


8、條款14:在資源管理類中小心coping行為
禁止復制。許多時候允許資源管理對象被復制是不合理的。應該將coping行為聲明為private。

對底層資源使用“引用計數器法”。
tr1::shared_ptr是一個絕好的實現手段,這個類在vs2005的庫中還沒有被加入,vs2008的c++標準庫包含了這個類,當然tr1的大部分類實現來自于boost,這個也不例外。

例如:

class Lock{
public:
     
explicit Lock(Mutex* pm) : mutexPtr(pm) 
     
{
              
lock(mutexPtr.get());
     }

     
/* 
        我們并沒有忘記析構函數,默認的析構函數會自動調用每個非static類變量的析構函數
            當mutexPtr 的引用計數為0就會調用智能指針的刪除器
    
*/

private:
    std::tr1::shared_ptr
<Mutex> mutexPtr;
};



9、條款
20:寧以pass-by-reference-to-constt替換pass-by-vaule

除了熟知的,傳遞const引用會比單純的值傳遞效率更高,應用傳遞還有意想不到的好處,多態。在參數為base class時,傳遞引用可以使虛函數被正確解析,而傳遞值將導致對象slicingbase class。

 在編譯器底層Reference往往是指針實現出來的,因此如果你有一個對象是內置類型,傳遞value往往比reference要高效些。對內置類型而言,當你有機會選擇采用pass-by-valuepass-by-reference-to-const時選擇前者并非沒有道理。這個忠告也適用于STL的迭代器和函數對象,因為他們習慣上被實現為passed-by-value。

在函數返回對象時謹慎使用reference 。除了*this其他的返回引用最好仔細斟酌。

 
請記?。簺Q不要返回一個pointer或者reference指向一個local stack對象,或返回一個reference指向一個heap-allocated對象,或返回pointer或者reference指向一個local static對象而有可能需要多個這樣的對象。如果要,考慮singleton吧。

 
10、條款22:將成員變量聲明為private

將成員變量聲明為private。protected不比public更具有封裝性。因為更改了protect變量將會影響雖有的derived class

 
11、條款23:寧以non-member、non-friend替換member函數(尤其是需要滿足交換律的operator)

C++不是純面向對象語言,不是所有的函數都定義在類中。

你不需要強行將所有函數定義在class內,因為這會造成class龐大的體積,而不同的用戶又可能對不同的方法感興趣。適當的拆分是有好處的。

 將所有的便利函數(uitlity funcation)放在多個頭文件中,但隸屬于同一個命名空間是C++標準庫的組織方式。

 因為在意封裝而讓函數成為classnon-member函數不意味它不可以是另一個classmember,它可以是某個工具類的static member函數。這讓純面向對象思維的java程序員感覺比較習慣。

 請記?。簩幙赡?/span>non-member non-friend函數替換member函數。這樣做可以增加封裝性、包裹彈性(packaging flexibility)和機能擴充性

 
12、條款24:若所有參數皆需類型轉換,請為此采用non-member函數

此條款一般用于實現operator時,為了滿足交換律和調用隱式類型轉換將operator在類外實現。是否聲明為friend看需要。

 
13、條款
34:區分接口繼承和實現繼承

Derived classes內的名稱會遮掩base classes內的名稱,他們不會被重載。public繼承下從來沒有人希望如此。

如何推翻C++對繼承而來名稱的缺省遮掩行為:

使用using聲明式使被遮掩的base class函數可見

using Base::funcation;

有時候你并不想繼承base classes的所有函數,這是可以理解的。但在public繼承下,這絕對不可能發生,因為它違反了public繼承所暗示的base classderived classes之間的is-a關系。(這也是為什么上述using 聲明被放在derived classpublic區域的原因:base classpublic名稱在derived class內也應該是public的)。然而在private繼承之下,它卻可能是有意義的。例如,假設Derivedprivate的形式繼承Base,以一個轉交函數完成對Base class函數的調用。(private是對Derived classes的一種協助)

 

 這也是為什么在copy constructorcopy assignment中必須調用base class的內容的原因。因為它們被drived class的隱藏了,不會被繼承。

條款12

 
14、條款
34:區分接口繼承和實現繼承

pure virtual函數、impure virtual函數、non-virtual函數之間的差異,使得你得以精確指定你想要derived class繼承的東西:只繼承接口(pure virtual),或是繼承接口和一份缺省實現(virtual),或是繼承接口和一份強制實現(non-virtual)。

pure virtual函數只具體指定接口繼承

impure virtual函數具體指定接口繼承及實現繼承

non-virtual 函數具體指定接口繼承以及強制性實現繼承,non-virtual函數會為該class建立起一個不變性,凌駕其特異性。你最好絕不重新定義繼承而來的non-virtual函數。

否則如:

class D{

public:

void mf();

}


class D : public B / *… */ };

D x;

*pD = &x;;

*pB = &x;

pD
->mf();

pB
->mf();

這兩個調用將調用不同的mf,因為mf是靜態綁定的,而不像virtual是動態綁定的。

就是因為同樣的道理,一個derived class絕不應該重新定義一個繼承而來的non-virtual析構函數。

 
15、條款35:考慮virtual函數以外的其他選擇

Non-Virtual Interface手法
一個有趣的思想流派主張virtual函數應該總是被實現為private。這一基本設計,也就是“令客戶通過public non-virtual函數間接調用private virtual函數”,稱為non-virtual interface手法。是template method設計模式的一個特例。Effective C++的作者把這個non-virtual函數成為virtual函數的wrapper。

NVI函數的一個優點是可以在執行virtual函數的特化行為之前和之后,做一些公共的初始化和清理工作。如果讓客戶直接調用virtual函數就沒有任何好辦法做這些事。

有些事情看似比較怪異,你在derived class中實現一個derived class從不調用的virtual函數。但這并不存在矛盾。重新定義表示某些事情如何被完成,而調用他們表示何時被完成,base class只是保留了“函數合適被調用的”權利。一開始這些聽起來有些詭異,但是C++這種derived class”可重新定義被繼承來的private virtual函數“的規則完全合情合理。

另外一種情況,使用Strategy模式
使用函數指針代替virtual函數,這樣是Strategy模式的一個簡單應用。這樣做的優點是同一個類型的實體可以有不同的運算實現方式(實體作為參數傳入)。但這樣做,指針指向的函數只能訪問public內容,如果要訪問private內容只能降低封裝。

便利設施:借由boost和tr1::funcation實現Strategy模式會得到高于函數指針的彈性(flexibility)。


16、條款
37:絕不重新定義繼承而來的缺省參數值

缺省參數是靜態綁定的,如果在virtual函數內改變,將會出現函數調用和參數不符合的結果。如果在non-virtual…條款34里貌似說過不要改變non-virtual函數的實現

 
18、條款39:明智而審慎地使用private繼承

Private 繼承意味著 is-implemented-in-terms of(根據某物實現出)。它通常比復合(組合)的級別低。但是,當derived class要重新定義繼承而來的virtual函數時或者要訪問protected base class的成員時,這種設計是合理的。

和復合不同,private繼承可以造成empty base的最優化。這對致力于“對象尺寸最小化”的程序開發者(特別是嵌入式程序員)而言,可能很重要。

 
19、條款40:明智而審慎的使用多重繼承

對于一個從Java陣營轉入C++的程序員而言多重繼承一般不會被使用。

 如果確實需要,請注意“鉆石”繼承的出現,即一個子類的繼承鏈上重復出現了同一個base class,這樣base class的成員變量會經每一條路徑被復制。解決的方式是virtual繼承,但是virtual繼承會增加大小、速度、初始化(及賦值)復雜度成本。如果virtual base classes不帶任何數據,將是最具使用價值的情況。

 多重繼承的確有正當用途。其中一個情節設計“public繼承某個Interface class”和“private繼承協助實現某個class”的兩相組合。

 
20、條款
42:了解typename的雙重意義

聲明templateclasstypename可以互換。

但是考慮這種情況:

template<typename C>

void print2md(const C& container)
{

       C::const_iterator
* x;

}


C
是在編譯器被解析的,而在編譯期編譯器并不知道C里面到底有什么。一種很不幸的事實,萬一C中有一個變量是const_iterator,而有一個全局變量為x。這會是一場災難。一種避免的方案就是使用typename聲明這是一個類型
template<typename C>

void print2md(const C& container)
{

       Typename C::const_iterator
* x;

}

請記住:

聲明template參數時,前綴關鍵字classtypename可互換

請使用關鍵字typename標示嵌套從屬類型名,但不能在base class listsmember initialization list內以它作為base class修飾符。

 

 

Virtual void mf1()
{

       Base::mf1();           
// 最好暗自轉換成inline

}

posted on 2009-03-29 10:54 弱水一瓢 閱讀(347) 評論(0)  編輯 收藏 引用


只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


<2025年12月>
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

導航

統計

文章分類

最新評論

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲精品欧美日韩专区| 亚洲欧美欧美一区二区三区| 国产精品久久久久久久一区探花| 美女网站久久| 国产日韩精品一区| 亚洲日本va午夜在线影院| 国产麻豆综合| av不卡在线观看| 亚洲国产精品尤物yw在线观看| 亚洲欧美日韩国产一区二区三区| 亚洲毛片在线| 免费观看30秒视频久久| 久久青青草原一区二区| 国产精品羞羞答答xxdd| 日韩午夜在线播放| 一区二区欧美在线观看| 欧美精品www在线观看| 欧美成人精品福利| 黄色工厂这里只有精品| 久久国产主播精品| 久久成人这里只有精品| 国产精品久久久| 一区二区三区免费在线观看| 这里只有精品视频| 欧美天堂亚洲电影院在线播放| 亚洲激情在线视频| av成人免费在线| 欧美日韩国产影片| 日韩一区二区免费高清| 中国成人亚色综合网站| 欧美日韩视频在线一区二区观看视频| 亚洲国产精品综合| 99精品热视频| 国产精品久久久久9999| 亚洲欧美综合精品久久成人| 久久不射2019中文字幕| 国内精品久久久久伊人av| 久久乐国产精品| 亚洲成色www8888| 亚洲美女色禁图| 国产精品高潮呻吟久久av无限 | 在线午夜精品自拍| 亚洲四色影视在线观看| 国产精品夫妻自拍| 欧美在线电影| 亚洲国产精品黑人久久久| 在线亚洲自拍| 国产精品爽爽爽| 久久久久成人精品| 亚洲国产精品成人综合色在线婷婷| 99在线精品视频在线观看| 国产精品草草| 久久久av水蜜桃| 国产精品美女久久久久av超清| 亚洲欧美国产制服动漫| 久久永久免费| 亚洲看片网站| 国产日韩av在线播放| 老司机午夜精品| 一本久道久久综合狠狠爱| 欧美一区国产一区| 亚洲精品乱码久久久久久蜜桃91 | 久久一区二区三区四区| 亚洲人成在线免费观看| 欧美伊人久久久久久久久影院| 精品999日本| 欧美日韩国产精品| 久久婷婷激情| 亚洲一区二区三区在线看| 老司机一区二区三区| 一本色道**综合亚洲精品蜜桃冫| 国产亚洲一区精品| 欧美日韩国产天堂| 久久久久久久久久看片| 一区二区三区你懂的| 另类人畜视频在线| 亚洲欧美综合另类中字| 亚洲激情网站| 国产字幕视频一区二区| 欧美日韩午夜在线| 欧美成人精品高清在线播放| 亚洲视频日本| 亚洲成人在线网| 国产欧美精品va在线观看| 欧美精品色网| 免费黄网站欧美| 午夜综合激情| 一本久久青青| 亚洲精品综合精品自拍| 免费亚洲一区| 久久视频一区| 久久精品国产精品亚洲综合| 亚洲午夜在线视频| 亚洲国产中文字幕在线观看| 国产亚洲精品久久飘花 | 国产精品国产三级国产普通话蜜臀 | 久久精品国语| 亚洲欧美国产精品桃花 | 亚洲夫妻自拍| 久久综合给合久久狠狠狠97色69| 亚洲一区二区三区在线播放| 亚洲精品免费在线观看| 在线精品高清中文字幕| 国产亚洲永久域名| 亚洲欧洲在线免费| 欧美成人亚洲成人日韩成人| 久久久www成人免费无遮挡大片| 性欧美办公室18xxxxhd| 亚洲一区影音先锋| 亚洲一区二区少妇| 亚洲一区免费视频| 亚洲欧美区自拍先锋| 亚洲午夜国产成人av电影男同| 99视频日韩| 在线性视频日韩欧美| 亚洲神马久久| 亚洲男女自偷自拍图片另类| 亚洲欧美日韩综合aⅴ视频| 亚洲一区中文字幕在线观看| 亚洲一区视频在线| 亚洲在线免费视频| 亚洲欧美日韩精品久久奇米色影视 | 欧美国产日韩一二三区| 欧美日韩国产在线观看| 国产精品99免费看| 国产乱码精品一区二区三区五月婷 | 亚洲第一精品福利| 亚洲高清网站| 一区二区三区日韩在线观看| 亚洲一区二区三区免费视频| 欧美一区日韩一区| 鲁大师影院一区二区三区| 欧美精品少妇一区二区三区| 国产精品成人免费| 狠狠色伊人亚洲综合成人| 亚洲激情国产| 亚洲一区二区三区高清不卡| 久久成人一区二区| 亚洲电影免费观看高清完整版| 亚洲精品乱码久久久久久日本蜜臀| 亚洲午夜小视频| 久久精品国产91精品亚洲| 欧美成人一区二区三区| 国产精品国产三级欧美二区| 国产视频观看一区| 亚洲美女视频在线观看| 欧美一区二区三区另类| 欧美大片网址| 亚洲香蕉伊综合在人在线视看| 久久九九国产精品| 欧美日韩在线播| 亚洲福利在线观看| 亚洲欧美在线网| 亚洲大胆av| 欧美一区二区三区久久精品| 欧美久久影院| 狠狠入ady亚洲精品经典电影| 一区电影在线观看| 女同性一区二区三区人了人一| 99在线精品视频在线观看| 久久久精品国产99久久精品芒果| 欧美日韩在线观看视频| 又紧又大又爽精品一区二区| 亚洲欧美激情四射在线日 | 久久精品国产久精国产爱| 欧美巨乳波霸| 激情亚洲网站| 欧美在线播放高清精品| 亚洲精品一区二区三区四区高清| 久久久99精品免费观看不卡| 国产精品看片你懂得| 一本到12不卡视频在线dvd| 美国三级日本三级久久99| 亚洲一区二区在线播放| 欧美另类99xxxxx| 亚洲国产91色在线| 久久综合久久美利坚合众国| 亚洲午夜视频| 国产精品s色| 一本色道久久88综合亚洲精品ⅰ| 欧美国产日本高清在线| 久久九九精品| 精品成人一区二区| 久久精品成人| 欧美一区日本一区韩国一区| 国产欧美综合一区二区三区| 亚洲欧美另类在线观看| 9i看片成人免费高清| 欧美激情第一页xxx| 最新精品在线| 欧美成人免费在线观看| 久久久噜噜噜久久中文字幕色伊伊| 国产亚洲女人久久久久毛片| 校园激情久久| 欧美一区二区三区视频在线 | 性色av一区二区三区红粉影视| 国产精品美女主播| 欧美伊人久久久久久午夜久久久久| 亚洲影院一区| 国产亚洲综合性久久久影院|