七、模板與泛型程式設計
條款41:了解隱式介面和編譯器多型
1、物件導向
1)顯式介面
型別必須支援class的介面,在原始碼中明確可見。基於函式簽名式
2)執行期多型
對於某些virtual成員函式,執行時根據動態型別決定呼叫哪個函式
2、template及泛型程式設計
1)隱式介面
型別支援的介面,有template中的需要決定。基於有效表示式
2)編譯器多型
以不同的template引數具現化function template會導致呼叫不同的函式
3、請記住
1)class和template都支援介面和多型
2)對class而言介面是顯式的,以函式簽名為中心,多型則是通過virtual函式發生於執行期
3)對template引數而言,介面是隱式的,基於有效表示式,多型則是通過template具現化和函式過載解析發生於編譯期
條款42:了解typename的雙重意義
1、class和typename
templateclass widget;
templateclass widget;
兩個宣告式意義完全相同
2、必須使用typename的情形
從屬名稱:template內出現的名稱相依與某個template引數
巢狀從屬名稱:從屬名稱在class內呈巢狀狀
c++解析規則:在template中遭遇巢狀從屬名稱,便假設不是型別,除非告訴它!
template
void print2nd(const c& container)
}注:只被用來驗證巢狀從屬型別名稱,其它名稱不該有!
3、規則例外
1)不可出現在base class list內的巢狀從屬型別名稱之前
2)不可在member initialization list(成員初值列)中作為base class修飾符
4、請記住
1)宣告template引數時,class和typename可互換
2)請使用typename標識巢狀從屬型別名稱,但不得在base class list(基類列)或member initialization list(成員初始列)內以它作為base class修飾符
條款43:學習處理模板化基類內的名稱
1、template繼承
繼承的base class,包含template引數,不到被具現化無法確切知道它是什麼
2、模板全特化
例子:template<> //既不是template也不是標準class。而是乙個特化版的template
class msgsender;
當base class被指定為msgsender時,未提供sendclear函式,編譯被拒絕!
原因:base class有可能被特化,而特化版本可能不提供和一般性template相同的介面,拒絕在模板化基類中尋找繼承來的名稱
解決方法:
1)在base class函式呼叫動作之前加上"this->"
this->sendclear(info);
2)使用using宣告式
using msgsender::sendclear;
編譯器進入base class作用域查詢
3)明確指出被呼叫函式位於base class
msgsender::sendclear(info);
問題:如果被呼叫的是virtual函式,明確資格修飾會關閉"virtual繫結行為"
3、請記住
可在derived class template內通過"this->"指涉base class template內的成員名稱,或寫出"base class資格修飾符"
條款44:將與引數無關的**抽離template
1、template重複
重複是隱晦的,需要注意template被具現化多次時可能發生的重複
2、請記住
1)template生成多個class和多個函式,所以任何template**都不該與某個造成膨脹的template引數產生相依關係
2)因非型別模板引數造成的**膨脹,可以消除,做法是以函式引數或class成員變數替換template引數
3)因型別引數造成的**膨脹,可降低,做法是讓帶有完全相同二進位制表述的具現型別共享實現碼
條款45:運用成員函式模板接受所有相容型別
1、智慧型指標
行為像指標的物件,可以在正確的時間自動刪除heap-base資源
真實指標支援隱式轉換,derived class指標可以隱式轉換為base class指標,"指向non-const物件"的指標可以轉換為"指向const物件"
2、同一template具現體
同一template的不同具現體之間並不存在什麼與生俱來的固有關係
例子:如果帶有base-derived關係的b,d兩型別分別具現化某個template,產生出來的兩個具現體並不帶有base-derived關係
3、template和泛型程式設計
1)member function template
對任何型別t和任何型別u,可以根據smartptr生成smartptr
泛化copy建構函式:建構函式根據物件u建立物件t,u和t的型別是同乙個template的不同具現體
template
class smartptr
t* get() const
private:
t* heldptr;
};使用成員初值列初始化型別為t*的成員變數,並以型別為u*的指標作為初值
只有存在某個隱式轉換可將乙個u*指標轉為乙個t*指標時才能通過編譯!
4、請記住
1)請使用member function template生成"可接受所有相容型別"的函式
2)如果你宣告member template用於"泛化copy構造"或"泛化assignment操作",還需要宣告正常的copy建構函式和copy assignment操作符
條款46:需要型別轉換時請為模板定義非成員函式
1、template實參推導
template實參推導過程並不將隱式型別轉換函式考慮!不會使用"通過建構函式而發生的"隱式型別轉換
2、friend函式
template
class rational
};template
const rationaloperator*(const rational& lhs, const rational& rhs);
當onehalf被宣告為rational,class rational被具現化出來,friend函式operator*(接受rational)也就被自動宣告出來
3、請記住
編寫class template,提供於此template相關的函式支援所有引數的飲食型別轉換時,定義函式為class template內部的friend函式
條款47:請使用traits classes表現型別資訊
1、stl迭代器分類
1)input迭代器
只能向前移動,一次一步,只能讀不能寫,只能讀一次。
例:istream_iterator
2)output迭代器
只能向前移動,一次一步,只能寫,而且只有一次。
例:ostream_iterator
3)forward迭代器
基於前兩者,而且讀寫次數一次以上
例:slist,tr1 hash
4)bidirectional迭代器
基於前三,而且可以向前向後
5)random迭代器
基於前四,可以執行"迭代器算術"
2、請記住
1)traits classes使得"型別相關資訊"在編譯器可用,它們以template和templates特化完成實現
2)整合過載技術後,traits classes有可能在編譯期對型別執行if...else測試
條款48:認識template元程式設計
1、請記住
1)template metaprogramming(tmp,模板元程式設計)可將工作由執行期移往編譯期,實現早期錯誤偵測和更高的執行效率
2)tmp可被用來生成"基於政策選擇組合"的客戶定製**,也可避免生成對某些特殊型別並不適合的**
《Effective C 》模版與泛型程式設計
item41 了解隱式介面和編譯期多型 縱使你從未使用過templates,應該不陌生 執行期多型 和 編譯期多型 之間的差異。因為它類似於 哪乙個過載函式該被呼叫 發生在編譯期 和 哪乙個virtual函式應該被繫結 發生在執行期 之間的差異。加諸於template引數身上的隱式介面,就像加諸於c...
七 模板與泛型程式設計 條款41 43
從乙個函式解讀隱式介面和編譯期多型 templatevoid doprocessing t w 隱式介面 從這段 來看,w物件要支援size,normalize,swap函式,也要支援比較函式,這就是t必須支援的一組隱式介面。編譯期多型 涉及w物件的任何呼叫,都有可能造成template的具現化。這...
模板與泛型程式設計
模板是泛型變成的基礎。泛型程式設計 編譯與型別無關的 是一種復用的方式,模板分為模板函式和模板類。模板函式是乙個通用的函式模板,而不是為每一種型別定義乙個新函式,乙個函式模板就像乙個公式,針對不同型別函式生成不同的函式版本。關鍵字 template 以 template 開始,後面跟乙個模板引數列表...