#雜記#構造函數

//來自於筆記整理。

類在使用時,需用到構造函數。

構造函數是與類同名的函數,如

class Node
{
    Node()
    {
        函數體
    }
};

先可以理解爲定義結構體時會通過Node()這個函數來初始化類,接下來會有更準確的解釋。

如果沒有編寫構造函數,則系統會自動創建構造函數,此構造函數沒有參數,函數爲空,即什麼都不做。

在使用時,常常不止一個構造函數,適用於函數重載原理(函數名相同,參數列表不同,系統通過參數列表來判斷選定函數)。

構造函數中有一類特別的,叫做拷貝構造函數,也稱爲複製構造函數,這個函數也是必須存在的,如果沒有編寫拷貝構造函數,系統會自動生成一個,但是如果類中有指針變量成員,此時會存在風險(淺拷貝,接下來會有解釋),所以良好的編寫習慣是類中編寫構造函數與拷貝構造函數。

複製構造函數中有一個形參,該形參是所在類 類型的引用,如

class Node
{
    Node(const Node&);
};

形參常用const修飾。

接下來引申一下初始化的過程。

類的初始化有兩種,複製初始化和直接初始化,簡單來區分,就是複製初始化用=,直接初始化用(),但是在本質上,有較大的區別。

以下情況,拷貝構造函數會被調用:

 

  1. 一個對象以值傳遞的方式傳入函數體
  2. 一個對象以值傳遞的方式從函數返回
  3. 一個對象需要通過另一個對象進行初始化

自定義拷貝構造函數是一種良好的習慣,可以提高編碼效率,並減少風險(淺拷貝)。

直接初始化的實現是直接調用與實參匹配的構造函數,複製初始化總是調用複製構造函數(更準確地說,總是需要用到構造函數),複製初始化是使用指定的構造函數(注意,這裏不一定是複製構造函數)創建一個臨時對象,再利用複製構造函數將臨時對象複製到目標函數,所以如果你自己定義複製構造函數並設爲private,那麼所有的複製初始化都無法執行,系統自動創造的複製構造函數是public的。

由於複製初始化總等價於直接調用複製構造函數進行初始化,所以編譯器常常會對複製初始化進行優化。

這也就造成了複製初始化與直接初始化的效率差異,通常來說,直接初始化與複製初始化僅在低級別的優化上存在差異,但對於不支持複製的類型,就擁有本質區別。

最後談談不編寫複製構造函數的危險性,即淺拷貝(位拷貝)與深拷貝。

如果由系統自動生成複製構造函數,且該構造函數完成對象與對象之間的拷貝,那麼就叫淺拷貝。

如果實行淺拷貝,如A=B,B中存在一個指針變量成員,並且已經申請了內存,那A中的指針變量成員就指向同一塊內存,如果B中指針成員內存被釋放,那A會成爲野指針。

故換個角度說,如果一個類擁有資源,當類複製過程中,資源沒有重新分配,就是淺拷貝。相反,如果資源重新分配(如申請內存),則爲深拷貝。

 

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