Effective C (七)模板與泛型程式設計

2021-06-13 10:04:14 字數 4205 閱讀 1977

七、模板與泛型程式設計

條款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 開始,後面跟乙個模板引數列表...