終於進到第四章 —— Designs and Declarations!許多概念都和前面的内容相關聯,建議先簡單複習後再次出發。
良好的 interface 設計應保持一致性,並讓行為與內建型別相容。假設我們設計一個名為 YoyoBirthday
的 class,它的建構函數需要傳入年月日。直接用三個 int
參數當作「年」、「月」、「日」容易混淆,更好的做法是分別定義參數的專屬型別。
此外,可以在「月」的 class 裡提供類似 January()
的靜態函式,而不是直接用 enum
或 static const
。
其他防止參數傳遞錯誤的方法包括:
const
,或盡可能使用 const
修飾函式。operator+
應與數學加法的行為一致。std::shared_ptr
等智慧指標以自動管理資源,避免讓使用者手動 delete
釋放資源。設計 class 其實就是設計 type。在定義新型別之前,務必考慮以下所有關鍵問題:
setter
方法或其他成員函數中檢查數值是否合理。+
、=
或比較運算符。delete
或 default
。public
、protected
或 private
,並考慮是否需要 friend function。Reference 支持多型,可以正確傳遞基底類別和衍生類別的物件。若對上述名詞感到陌生,可以參考知識點 7 和知識點 9。
通常偏好以 pass-by-reference-to-const 而非 pass-by-value 傳遞,因為它通常更高效且能避免 slicing 問題。Pass-by-value 會透過 copy constructor 進行數值和物件的複製,結束後還需浪費額外的性能調用 destructor。使用 const
引用可以避免這些操作。
此規則不適用於內建型別以及 STL 的 iterator 和 function object 類型。
雖然在函數的參數傳遞中用 reference 通常效率更高,但在 return
中直接返回 reference 往往會引發問題!
new
產出的 heap object 的 reference:雖然理論上可行,但產生的物件需要手動管理,否則容易導致資源泄漏。const Rational& operator*(const Rational& lhs, const Rational& rhs) {
Rational* result = new Rational(lhs.n * rhs.n, lhs.d * rhs.d);
return *result;
}
const Rational& operator*(const Rational& lhs, const Rational& rhs) {
static Rational result;
result = Rational(lhs.n * rhs.n, lhs.d * rhs.d);
return result;
}
總結來說,理想的方式是直接返回一個新的物件 value,並依靠編譯器的運算優化來減少性能損耗。同時,value 有清晰的所有權,不會影響使用者對資源的管理。