《Effective C 》第四章 設計與宣告

2021-08-03 02:50:57 字數 1823 閱讀 2680

條款20:寧以pass-by-reference-to-const替換pass-by-value

這個條款其實也可以用pass-by-pointer-to-const來替代。因為如果傳值,對於使用者自定義型別來說十分費時,而使用const型別的引用或者指標來傳遞,不僅省時,而且保護了原物件不會被修改。但是對於內建型別、stl的迭代器(不是很懂)來說,傳遞value往往更合適。

條款21:必須返回物件時,別妄想返回其reference

原因很明確,函式返回時,一般返回的是區域性變數,local物件在函式退出前就被銷毀了,如果返回引用,則會出現錯誤。你可能會提出在函式內建立乙個heap上的物件,這樣就不會被銷毀。但是這同樣得付出乙個建構函式的代價,同時誰該對這個heap物件呼叫delete?很容易出現記憶體洩漏。因此還是老老實實返回value,編譯器會為其優化,即nrv。

條款25:考慮寫出乙個不丟擲異常的swap函式

我們考慮一下標準庫提供的swap函式:

namespace std

}

這個版本 swap實現比較平淡,效率比較低下。對於一些型別而言,這樣複製完全沒必要,比如「以指標指向乙個物件,內含真正資料」的型別:

class widgetimpl

;class widget

};

一旦要swap兩個widget物件,我們所需要做的只是交換它們的pimpl指標。但是stl提供的預設版本效率讓人...或許我們可以為這個函式針對widget特化:

namespace std

}

很遺憾,不能通過編譯。因為pimpl是私有成員,不能直接訪問,或許我們可以為widget定義乙個成員函式:

void widget::swap(widget &other)

//然後在特化版本裡呼叫成員函式

namespace std

}

看起來十分美好,不僅能夠通過編譯,還與stl具有一致性。然而假設widget和widgetimpl都是類模板:

templateclass widgetimpl{};

templateclass widget{};

在widget內放個swap成員函式,我們卻在特化std::swap時候的出現錯誤:

namespace std

}

問題在於c++不支援對函式模板進行偏特化,只支援全特化。因為對函式模板進行偏特化通常可以簡單為其增加乙個過載來解決這個問題。但是由於swap屬於std特殊命名空間,我們可以全特化std內的templates,但是不能新增新的templates。那該怎麼辦?我們可以自己定義乙個命名空間,如下:

namespace widgetstuff

}

目前我們所寫的每一樣東西都和swap編寫者有關係。如果從客戶觀點看,假如你正在寫乙個function template,需要交換兩個物件的值,你並不知道要呼叫哪個版本的swap,或者你並不知道有哪些版本的swap可供呼叫,或許下面的做法能夠達到比較好的效果:

templatevoid func(t &obj1, t &obj2)

如果t是位於widget並位於widgetstuff內,編譯器會使用此命名空間內的swap函式,如果沒有專屬的swap函式存在,則呼叫std::swap的函式,這得感謝using為其增加可見。

Effective C 學習筆記之第四章(1)

chapter 4 設計與宣告 item18 讓介面容易被正確使用,不易被誤用 理想情況下應該是如果能編譯通過,那麼介面一定能實現你想要的,否則就不能編譯 假設正在設計乙個表示時間資料的類的建構函式 date int month,int day,int year 這樣會出現兩個問題,一是傳參的順序不...

js 設計模式 第四章

繼承 why?多個類公用的功能,如果重複拷貝,一方面,工作量大,另一方面,如果公用功能需要修改,則需要修改所有類中的這個功能,重複工作量大。為了減少複製以及帶來的不利於修改的問題,我們需要繼承 how?三種方法 classical inheritance prototypal inheritance...

第四章 繼承

一 為什麼要繼承 在物件導向中我們將具有很多重複內容的類中的內容提取出來,寫成乙個單獨的類 其他類只需要繼承就能取得這些功能,同時可以在自己類中寫入獨特的自定義方法 二 繼承語法 inte ce circle nsobject 繼承是在介面中定義的 冒號後的類名是要整合的類,nsobject 是co...