條款44:運用成員函式模板接受所有相容型別
(use member function templates to accept "all compatible types.")
內容:不知道大家注意到沒有,在類的繼承體系中,物件指標一直在為我們做一件很好的事情:支援隱式轉換(implicit conversions).derived class指標可以隱式轉換為base class指標,"指向non-const物件"的指標可以轉換為"指向const物件"......等等.下面例子展示了繼承體系之間的可能進行的轉換操作:
class top;
class middle:public top;
class bottom:public middle;
top* top1 = new middle; //將middle*轉換為top*
top* top2 = new bottom; //將bottom*轉換為top*
const top* const_top2 = top1; //將top*轉換為const top*
在前面的條款13中我們提到,像std::auto_ptr和tr1::shared_ptr這樣的智慧型指標,能夠提供原始指標沒有的機能.比如能夠在正確的時機自動刪除heap-based資源.本款中我們自然就想到了,如果智慧型指標也能支援上述的隱式操作轉換,那豈不是很方便.於是我們在這裡試圖讓類似下面的**通過編譯:
template
class smartptr;
smartptrtop1_smart_ptr = smartptr(new middle);
smartptrtop2_smart_ptr = smartptr(new bottom);
smartptrconst_top2_ptr = top1_smart_ptr;
但是,現實的情況好像並不是像我們想象的那麼美好:同乙個template的不同具現體(instantiation)之間並不存在故有的聯絡.也就是說,編譯器視smartptr和smartptr為完全不同的classes.它們之間沒有任何必然的聯絡.這個問題不小啊,但一想到如果smartptr classes之間具有了這樣的轉換能力,世界將會變的更加的美好.我就增強了要實現這種模擬的信心.好,接著往下看.
在上述繼承體系中,每一條語句都建立乙個新式智慧型指標物件,我們自然就想到了,我們應該把工作的焦點放在如何編寫智慧型指標的建構函式上,使其滿足我們的轉型需要.而稍微仔細的觀察一會兒,我們就有了乙個新的顧忌:我們永遠無法寫出我們需要的建構函式.為什麼呢?因為繼承基類的子類可以有很多個,每誕生乙個新的子類,我們就必須要在基類智慧型指標中新增乙個為實現其向子類轉換的新的建構函式.那樣的**不僅理解起來很晦澀,更難以維護.在如此"絕境"之下我們想到了模板成員函式,有了這樣的"利器"我們就在戰術上從被動為主動了,哈哈.
template
class smartptr;
等一下,建構函式為什麼沒有explicit修飾?我故意的.因為要完成原始指標之間的隱式轉換,我們需要支援這樣的操作.如果smartptr也像auto_ptr和tr1::shared_ptr一樣,提供乙個get成員函式去發揮智慧型指標物件的原始指標副本.上面的**我們可以寫的更清楚一點:
template
class smartptr //用other.held_ptr_初始化this->held_ptr_,這裡的other的原始物件如果是
//this原始物件的子類的話,這裡就完成子類向父類的隱式轉換過程.
t* get()const
...private:
t* held_ptr_; //這是smartptr持有的內建指標.
};呵呵,不錯吧!其實member function template(成員函式模板的效用不限於建構函式),它們常常扮演的另乙個角色就是支援賦值操作.這點在tr1的shared_ptr中獲得了絕好的發揮.下面是tr1規範中關於tr1::shared_ptr的乙份摘錄.
template
class shared_ptr;
這裡還有一點我們要注意:member template並不會改變語言規則.而在前面我們曾提到,如果程式需要乙個copy建構函式,你卻沒有宣告它,編譯器會為你暗自生成乙個.在class內申明泛化copy建構函式(member template)並不會阻止編譯器生成它們自己的copy建構函式(non-template),故你想要控制構造的方方面面,你必須同時宣告泛化copy構造和普通copy構造.賦值操作也是原因.下面的tr1::shared_ptr的定義摘要,就證明了這點是正確的:
template
class shared_ptr;
請記住:
■ 請使用member function template(成員函式模板)生成"可幾首所有相容型別"的函式
■ 如果你宣告member template用於"泛化copy構造"或"泛化assignment操作",你還需要宣告正常copy建構函式和copy assignment操作符.
Item 45 成員函式模板
stl容器使用的iterator幾乎都是智慧型指標,所以才能以 操作在節點之間移動。但真正的指標,支援隱式型別轉換 1 指向 派生類物件 的指標可以轉成指向 基類物件 的指標 2 指向 non const物件 的指標可以轉成指向 const物件 的指標 智慧型指標做不到這些。templateclas...
成員函式模板
1 背景 參考資料 1 p218的條款45 運用成員函式模板接受所有相容型別,提出了如何使得自定義的智慧型指標支援隱式型別轉換的方法,其中用到的技巧就是使用成員函式模板。關於其詳細的原理,書中已經說的很清楚,只是在程式設計的過程中會遇到挫折,故在此記錄一下成功通過的編譯的 見下一章 2 templa...
成員函式模板
真實指標支援隱式轉換 1 derived class指標可以隱式轉換為base class指標 2 指向non const物件 的指標可以轉換成 指向const物件 的指標。智慧型指標 必須編寫乙個成員函式模板。因為我們無法寫出所有的智慧型指標的建構函式,一旦derived體系有新的補充就又要根據其...