建構子與除構子


  1. Constructor (建構子) 與 destructor (除構子): 類別中特殊的成員函數, 編譯器會對它們作特殊的處理. 請參考 complex.cc, vector.cc, 與 creature.cc.
  2. 功用: 希望 (半自動或全自動地) 對每個變數做起始與清除的動作, 通常對應到 C 程式中名稱為 init/open/begin/start/... 與 shutdown/close/end/stop/... 等函數. 類似觀念: 視窗程式設計中的 open 與 close 等 event (事件) 的 script (腳本)
  3. 執行時機
    1. constructor: 變數生命開始時 (即自系統取得記憶空間時). 無參數的 constructor 自動執行; 有參數的 constructor 手動執行.
    2. destructor: 變數生命結束前 (將記憶空間還給系統前). 一律沒有參數, 系統會在適當時機自動呼叫.
    以變數的 life time 分別說明:
    1. 靜態變數: 進出整個程式時.
    2. 自動變數: 進出 block 時.
    3. free store 上的變數: new 與 delete 時.
  4. 宣告方式
    1. Constructor 名稱與類別名稱相同, 不可以有傳回值 (連 void 都不寫), 不應宣告為 const. 可以有好幾個 signature 不同的 constructors.
    2. Destructor 名稱與類別名稱相同, 但前面多了 ~. 一個類別只能有一個 destructor, 且不可以有傳回值 (連 void 都不寫), 不應宣告為 const, 也不可以有參數.
    3. 宣告可接受單一參數的 constructor (包含有多餘的內定參數者) 時, 記得在 constructor 名稱前面加上 explicit 這個 keyword; 稍後再解釋何時不必加. (定義處不要寫 explicit)
  5. 如何呼叫 constructor
    1. 宣告變數時, 例: complex x(3,-4), y(2,-1); 注意: local static 變數的 constructor 在該副程式第一次執行時起動.
    2. 以 new 產生變數時, 例: p = new complex(4,-3);
    3. 在 "上級" 類別的 constructor 中, "脖子" 處, 呼叫 "下級" 類別的 constructor, 例: explicit comlpex(double r, double i=0) : re(r), im(i) { } (稱為 constructor initializer) 以這個例子而言, 其實效果和
                      explicit complex(double r, double i=0)
                      {
                          re = r;     im = i;
                      }
              
      

      一樣. 但是 constructor initializer 的寫法比較具有一般性, 在很多情況下非用它不可, 例如
      1. data member 又是一個使用者自定的類別;
      2. data member 是一個 reference
      3. data member 是一個 const
      4. 在 initialize base class member 時 (見繼承單元)
    4. 產生用畢即棄的臨時變數, 例: complex(3,4).print();return complex(re + b.re, im + b.im);return complex(abs * cos(angle), abs * sin(angle));
    5. 注意: 即使宣告變數或使用 new 時不傳參數, 仍舊有一個 constructor 會自動執行 -- 也就是那個不需要參數的 constructor.
  6. 如何呼叫 destructor: No, never do that!
  7. Copy constructor (複製建構子)
    1. 宣告方式: complex(complex const & x)
    2. 執行時機:
      1. 給新宣告的變數設定起始值, 以舊的變數為範本, 例: complex x(3,4); complex y(x);
      2. 以值傳遞參數.
      3. 參數傳回值.
    3. 注意: 在變數宣告中, complex y = x; 會呼叫到 copy constructor; 但是在程式中, y = x; 呼叫到的則是 assignment operator.
  8. 以下四個特殊成員函數與 memory allocation 有關, 且同一個類別中, 修改這四個成員函數的程式碼時, 往往必須一起考慮.
    1. Constructor: new
    2. Destructor: delete
    3. Copy constructor: new, copy
    4. Assignment operator: (delete, new,) copy (記得檢查 src 與 dst 相同的特殊狀況.)
    結論: 要多少空間來, 就還多少空間回去, 最後一定要收支平衡.
  9. 內建版的特殊成員函數
    1. 上述四個特殊的 member functions 都有內建版. 內建的 constructor (沒有參數) 與 destructor 什麼都不作; 內建的 copy constructor 做的是: "逐一呼叫每個資料成員的 copy constructor"; 內建的 assignment operator 做的是: "逐一呼叫每個資料成員的 assignment operator". 在最底層 (也就是 int, double, char, ... 等內建型別) 的 copy constructor 與 assignment operator 都是直接拷貝整個變數.
    2. 如果程式設計師宣告了任何一個 constructor (不論是有參數的版本或沒有參數的版本), 則內建的 (沒有參數的) constructor 自動消失.
    3. 如果程式中需要宣告某一類別的陣列變數, 則該類別一定要有一個不具參數的 constructor (內建的或程式設計師定義的皆可)
    4. 在一個 composite class 中 (即類別的 data member 本身又是一個使用者自定的類別), 層層疊疊的 constructors 的呼叫順序是由下而上; 而 destructors 的呼叫順序則是由上而下. (想像蓋房子與拆房子的順序)