在建構函式內的工作

避免在建構函式內呼叫虛擬函式,並且在無法適當回報錯誤時,避免進行可能失敗的初始化。

定義

建構函式內可以執行任意的初始化動作。

優點

  • 不需要擔心類別是否已經初始化過了。
  • 已經經過建構函式充分初始化的物件可以作為 const 使用,而且與標準容器與演算法使用時更容易。

缺點

  • 如果在建構函式內呼叫虛擬函式,這些呼叫不會被轉發至子類別的實作。 即使你的類別目前沒有子類別,未來的修改可能會悄然引入這個問題,造成困惑。
  • 建構函式沒有簡單的方法來回報錯誤,除了直接讓程式崩潰 (這並不總是合適) 或使用例外 (也被我們 禁止 了)。
  • 如果工作失敗了,那我們此時就會有個初始化失敗的物件。 這時可能需要提供 bool IsValid() 之類的方法來檢查狀態,但這種機制容易被遺漏,導致錯誤。
  • 由於無法取得建構函式的函式指標,因此建構函式內的工作難以被移交,例如交給另一個執行緒。

決定

建構函式應該永遠不要呼叫虛擬函式。 在適當的情況下,終止程式可能是一種合理的錯誤處理方式。 否則,可以考慮像 TotW #42 所述那樣建立工廠方法 (Factory Method) 或者 Init() 方法。 避免在沒有其他狀態影響可呼叫公用方法的物件上使用 Init() 方法 (這類半建構狀態的物件特別難以正確使用) (譯註:這句話的意思是,如果沒有需要延遲初始化或者錯誤處理的需求,就不要特別為了初始化寫一個 Init(),而是使用建構函式進行初始化即可。)