條款20:寧以pass-by-reference-to-const 替換 pass-by-value
一般而言,pass-by-value 需要耗費調用拷貝建構函式和解構函式的代價。當傳回值以value返回時也同樣。
以by reference 方式傳遞參數還可以避免slicing(對象切割問題)。當一個derived class 對象以by value方式傳遞給一個函數類型為base class的形參,base class 建構函式會被調用,則造成derived對象被切割為base對象。
一般而言,可以合理假設“pass-by-value” 代價並不昂貴的唯一對象就是內建類型和STL的迭代器、以及函數對象。後兩者都是在指標的基礎上塑造出來。其他情況,盡量以pass-by-reference-to-const替換pass-by-value。前者通常比較高效,並可避免切割問題。
條款21:必須返回對象時,別妄想返回其reference
比如operator*操作符,不能妄想返回reference,應當返回一個以值返回的對象。
絕不要返回pointer或reference指向一個local stack對象(它們會指向或引用一個已經被銷毀的對象),或返回reference指向一個heap-allocated對象(無法delete掉這個對象了)。
條款22:將成員變數聲明為private
"封裝性” 要求這樣做:如果你通過函數訪問成員變數,日後可以更改這個成員函數的實現,而class客戶一點也不知道 class 內部實現已經變化。
public 的成員變數意味著不封裝,而幾乎可以說,不封裝就意味著不可改變,個別是對被廣泛使用的class而言。被廣泛使用的class是最需要封裝的,因為它們最能夠從”改變採用一個較佳的實現版本“中獲益。
protected成員變數的封裝性並不高於public,這令人驚訝。成員變數的封裝性與 "成員變數的內容改變時所破壞的代碼數量” 成反比。所謂改變,也許是從claas中移除它。移除public的成員變數,可以破壞不可預知量的客戶代碼。移除protected成員變數,可以破壞使用它的所有derived class客戶代碼,數量依然不可預知的大。因此,protect成員變數就像public一樣,缺乏封裝性。
一旦你將一個成員變數聲明為public或protected而客戶開始使用它,你就很難改變哪個成員變數所涉及的一切。從封裝的角度看,其實只有兩種存取權限:private(提供封裝)和非private(不提供封裝)。
小記:切記將成員變數聲明為private。這可賦予客戶訪問資料的一致性、可細微劃分存取控制(唯讀、唯寫、讀寫、不可訪問等)、允諾約束條件獲得保證,並提供class作者以充分的實現方法彈性。另外,protect並不比public更具封裝性。