[原創(chuàng)文章歡迎轉(zhuǎn)載,但請(qǐng)保留作者信息]
Justin 于 2010-04-26
看完以后覺得講的其實(shí)是如何用模板函數(shù)來讓拷貝構(gòu)造函數(shù)和賦值運(yùn)算符接受所有可能的輸入。
首先對(duì)于內(nèi)建類型的對(duì)象,他們作為函數(shù)參數(shù)時(shí),參數(shù)的類型轉(zhuǎn)換是自動(dòng)發(fā)生的。比如說派生類對(duì)象的指針,如果需要,會(huì)被轉(zhuǎn)換為其父類對(duì)象的指針。
而對(duì)于智能指針,要完成類似的轉(zhuǎn)換需要編寫額外的代碼才能實(shí)現(xiàn)。
如書中例子所示,如果類Base是類Derived的父類,對(duì)于下面的一個(gè)模板類:
template?<typename?T>
class?SmartPointer?{
public:
???explicit?SmartPointer(T?*?pointer);
//..
}
經(jīng)管這兩個(gè)智能指針指向的對(duì)象是有繼承關(guān)系的,SmartPointer<Base>和SmartPointer<Derived>對(duì)于編譯器來說完全沒有聯(lián)系。
于是,如果一個(gè)函數(shù)聲明了接受一個(gè)SmartPointer<Base>類型的參數(shù),就無法給它傳進(jìn)一個(gè)SmartPointer<Derived>類型的指針了。
為了能夠讓智能指針對(duì)象也具備一般指針的隱式轉(zhuǎn)換能力,首先可以做的工作是改造智能指針的構(gòu)造函數(shù),讓對(duì)象生成的時(shí)候可以依照具體情況“變態(tài)”成實(shí)際需要的對(duì)象類型。好吧,那我們現(xiàn)在就開始做……
打住!有兩個(gè)問題需要考慮:第一是我們?cè)趺粗乐悄苤羔槝?gòu)造函數(shù)的輸入?yún)?shù)pointer是什么類型?又怎么知道真正需要的目標(biāo)類型是什么?如果不知道我們?cè)趺磳戇@個(gè)構(gòu)造函數(shù)?第二是就算我們知道了輸入的類型和生成的類型,有多少種這樣的搭配是SmartPointer需要接受的?如果有100對(duì)不同的類型搭配,我們就要寫100種構(gòu)造函數(shù)嗎?
解決這些問題的辦法:用“模板化”的構(gòu)造函數(shù)。(member function templates)
template?<typename?T>
class?SmartPointer?{
public:
???template?<typename?U>
???SmartPointer(const?SmartPointer<U>&?input)?:?myPointer(?input.get()?)
???{//..
???}
???T*?get()?const?{?return?myPointer;?}
???//..
private:
???T*?myPointer;
};
上面的方案?jìng)€(gè)人感覺很繞,不過確實(shí)也解決了問題。
大概分析一下:
- 其中的構(gòu)造函數(shù)是一個(gè)模板函數(shù),接受參數(shù)為U類型的對(duì)象,構(gòu)造出指向T的指針。
- 但是很明顯我們不需要一個(gè)能夠接受任意類型再生成任意類型對(duì)象的構(gòu)造函數(shù)。這樣會(huì)天下大亂的。于是就有了get()對(duì)myPointer的初始化:構(gòu)造函數(shù)的輸入?yún)?shù)input所持有的指針是可以用get()來得到的,然后有這個(gè)“get”來的指針去初始化目標(biāo)對(duì)象所持有的指針,到了這一步,就和一般指針的隱式轉(zhuǎn)換沒有差別了:
- 如果可以轉(zhuǎn)換,智能指針SmartPointer<U>就順利轉(zhuǎn)換為SmartPointer<T>;
- 如果不能轉(zhuǎn)換,構(gòu)造函數(shù)就失敗。
- 這里的構(gòu)造函數(shù)沒有explicit修飾,因此類型的轉(zhuǎn)換是隱式的。如果真有這個(gè)必要,就加上explicit,這樣就需要顯式地聲明需要進(jìn)行類型轉(zhuǎn)換。
- 當(dāng)一個(gè)類沒有定義自己的構(gòu)造函數(shù)時(shí)(包括賦值構(gòu)造函數(shù)和拷貝構(gòu)造函數(shù)),編譯器會(huì)“幫你”創(chuàng)建默認(rèn)的構(gòu)造函數(shù)。編譯器不會(huì)理睬“模板化”的構(gòu)造函數(shù),如果一個(gè)類中只有“模板化”的構(gòu)造函數(shù),它還是會(huì)繼續(xù)生產(chǎn)默認(rèn)的構(gòu)造函數(shù)。因此,如果不想讓編譯器做多余的事,就有必要自己寫好非模板化的構(gòu)造函數(shù),以此讓編譯器“閉嘴”@#¥%