Effective C++ Note

一、對象使用前確定初始化 — Item 4
    
  類對象在使用前必須保證其初始化,注意和賦值的區別。雖然賦值操作有時可以實現相同的操作,但是某些時候可能會出問題。因此類的構造函數最好使用成員初值列來實現對象數據的初始化,而不是在函數中進行賦值。例: 

class Test{
public:
    Test(int a, int b);
private:
    int numx;
    int numy;
    int numz;
 };
 //這裏這個構造函數是採用賦值的方式給對象成員賦值
 Test::Test(int a, int b){  
     numx = a;
     numy = b;
     numz = 0;
     }
 //這裏這個構造函數是採用成員初值列的方式實現對象成員初始化
 Test::Test(int a, int b):numx(a),numy(b),numz(0){} 

  C++規定,對象的成員變量初始化操作發生在進入構造函數本體之前,因此,上面的第一個Test不是初始化,而是賦值,成員變量numx,numy,numz的初始化時間發生更早,是通過默認的構造函數進行初始化的。第二個Test與前一個結果相同,但是效率更高。這裏注意成員初值列的順序要與聲明順序相同,在C++中類成員變量總是以其聲明的次序初始化。
  
二、C++默認編寫並調用的函數 — Item 5

  在C++類中,如果沒有聲明,則編譯器會自動聲明下面幾個函數:default構造函數,copy構造函數,copy assignment構造函數,析構函數。copy構造函數就是利用對象來新建新的對象,copy assignment就是通過=來新建對象。
  若是有時不想編譯器默認聲明這幾個函數,可以將相應的成員函數聲明爲private並且不予實現,這樣在調用這樣的函數時編譯器就會提示拒絕。(I-6)

class A  //類,當不進行定義時,會有下面的函數自動定義
A(){}
A(const A&) {}
A& operator=(const A&){}
~A(){}
//分別表示下面的用法
A s1= A(); A(s2); A s3 = s2; 
//只有定義了相應類型函數才能使編譯器不提供默認版本

三、以對象管理資源 — Item 13

  在C++中管理資源是十分重要的,當一個對象創建之後並使用之後需要刪除它,但是在函數中有時可能無法做到絕對的會執行刪除命令,這裏可以用到auto_ptr指針來進行管理。C++的auto_ptr所做的事情,就是動態分配對象以及當對象不再需要時自動執行清理。用法如下:

int *p=new int(0);
auto_ptr<int> ptr1(p);

上面的指針p更多的是一個對象指針,auto_ptr類指針對象ptr1則用來管理p,當p用完時可以自動銷燬。

auto_ptr注意事項:

   1)auto_ptr不能共享所有權,即不要讓兩個auto_ptr指向同一個對象。
  2)auto_ptr不能指向數組,因爲auto_ptr在析構的時候只是調用delete,而數組應該要調用delete[]。
   3)auto_ptr只是一種簡單的智能指針,如有特殊需求,需要使用其他智能指針,比如share_ptr。
   4)auto_ptr不能作爲容器對象,STL容器中的元素經常要支持拷貝,賦值等操作,在這過程中auto_ptr會傳遞所有權,那麼source與sink元素之間就不等價了。
   參考:http://www.cnblogs.com/qytan36/archive/2010/06/28/1766555.html
   源碼參考鏈接

四、儘量使用const引用傳值 — Item 20

  在函數調用時,經常會有參數的存在,若是一般的簡單參數還好,可以直接將參數的值進行傳遞,但是有時會有一些複合類型的參數,例如某個類對象,或某個大的數組,若是直接傳遞值的化,函數調用過程中,會進行這些值的複製,對於類對象的參數還會創建對應參數的對象副本,這些新建的副本在函數調用完之後又要進行銷燬,這樣一個過程是比較浪費資源的。因此,在大多數時候,可以儘量採用引用的方式來進行參數傳遞(類似於指針傳遞),利用by-reference-const進行傳值比較高效,且可以避免切割問題。當然這種方式不適合內置類型及STL。

五、封裝性 — Item 22

  一般類成員變量都應聲明爲private,這樣擁有最好的封裝性,只有通過定義的成員函數纔可以對這些變量進行適當的訪問。protect的封裝性並不比public強,即這兩者的封裝性都很差。

六、繼承與面向對象設計

  對於public繼承來說,基類的所有特性都適用於派生類,因爲派生類對象也是一個基類對象。(I-32)
  
  派生類中的名稱會掩蓋基類中的名稱(主要爲函數),只與名稱有關,與相應的函數參數無關,函數一旦在派生類中作用域中調用則先在此作用域查找函數,若是沒有,則再擴大範圍,在基類作用域中查找(C++的名稱遮掩規則-作用域)。(I-33)

  在類繼承中,函數的繼承相當重要,在基類中函數的類型有幾種:純虛函數,一般虛函數,普通函數。純虛函數和虛函數都是在函數聲明前面加上virtual,純虛函數的話聲明時直接讓函數等於0。
  純虛函數在基類中沒有定義,在派生類中需要重新聲明,再根據需要定義函數體。在這裏派生類只是繼承一個接口,並無法獲得具體的實現繼承,具體的實現必須由派生類自己定義。
  一般虛函數與純虛函數區別就在於它提供了一個默認的實現繼承,派生類繼承這個接口,但是可以根據需要來決定是否重新定義函數體,如果不想重新定義,可以使用默認繼承,因爲基類中虛函數提供了一個默認的實現,這在純虛函數中是沒有的。(I-34)
  
  一般函數就是非虛函數,它也提供一個接口,但是也提供實現,且是強制性的實現繼承,不能進行改變。雖然在派生類中可以對基類的一般函數進行修改覆蓋,但是並不推薦這樣做,因爲對於一般函數它們是靜態綁定的,即調用哪個函數由對象的指針類型來決定。(I-36)
  
  策略模式Strategy(對象行爲型)。 (I-35)
  
  靜態類型,對象在聲明時所採用的類型,動態類型,對象當前所指的對象類型。一般出現於類繼承中,可以用基類來定義一個對象,則該對象的靜態類型爲該基類,再將該對象指向一個派生類的對象,則此時,該對象的動態類型變爲了派生類類型。在函數繼承中不要重新定義一個繼承而來的缺省參數值,缺省參數是靜態綁定的,而繼承的virtual函數唯一應該覆蓋的東西是動態綁定。(I-37)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章