(本文最初發(fā)表于程序人生 >> Member Function Templates(成員函數(shù)模板) 作者:代碼瘋子)Member Function Templates翻譯成中文就是成員函數(shù)模板,這個(gè)東西我個(gè)人見(jiàn)得少,最初是在STL的auto_ptr源代碼里面看到的,當(dāng)時(shí)候也不是很明白;這幾天又翻了翻《More Effective C++》,正好看到上面介紹的比較詳細(xì),就找了點(diǎn)資料總結(jié)一下。
為了更好的說(shuō)明問(wèn)題,我們自己定義一個(gè)Smart Pointer(智能指針,這里只是示例,所以定義是不完整和不完善的),假設(shè)現(xiàn)在我們手上有這樣三個(gè)類(lèi):MusicProduct、CD、MP3,類(lèi)之間的關(guān)系圖如下:

我們定義的智能指針SmartPtr如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| template<class T>
class SmartPtr
{
public:
explicit SmartPtr(T* realPtr = NULL) : pointee(realPtr){}
T* operator->() const
{
return pointee;
}
T& operator*() const
{
return *pointee;
}
private:
T* pointee;
}; |
現(xiàn)在有一個(gè)播放函數(shù):
1
2
3
4
5
6
7
8
| void displayAndPlay(const SmartPtr<MusicProduct>& pmp, int times)
{
for (int i = 1; i <= times; ++i)
{
pmp->displayTitle();
pmp->play();
}
} |
如果有下面這樣的調(diào)用,會(huì)不會(huì)有什么問(wèn)題呢?
1
2
3
4
5
6
7
8
9
10
11
12
13
| int main(int argc, char **argv)
{
CD *cd = new CD("BEYOND LIVE CD");
MP3 *mp3 = new MP3("BEYOND MP3");
SmartPtr<CD> cdMusic(cd);
SmartPtr<MP3> mp3Music(mp3);
displayAndPlay(cdMusic, 10);
displayAndPlay(mp3Music, 10);
return 0;
} |
實(shí)際編譯時(shí)會(huì)發(fā)生錯(cuò)誤,在Visual Studio 2008下面提示如下錯(cuò)誤:
1>error C2664: “displayAndPlay”: 不能將參數(shù) 1 從“SmartPtr<T>”轉(zhuǎn)換為“const SmartPtr<T> &”
1> with
1> [
1> T=CD
1> ]
1> and
1> [
1> T=MusicProduct
1> ]
1> ......
提示“SmartPtr”不能轉(zhuǎn)換為“const SmartPtr &” 。因?yàn)樵诰幾g器眼里SmartPtr和SmartPtr是兩個(gè)完全不相關(guān)的東西,他們之間沒(méi)有繼承關(guān)系。我們可以寫(xiě)一個(gè)隱式類(lèi)型轉(zhuǎn)換,但實(shí)際操作起來(lái)不太理想,正如前面所說(shuō),STL的auto_ptr采用了Member Function Templates(成員函數(shù)模板)技術(shù)。我們可以再SmartPtr的定義中增加成員函數(shù)模板實(shí)現(xiàn)代碼,具體如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| template<class T>
class SmartPtr
{
public:
explicit SmartPtr(T* realPtr = NULL) : pointee(realPtr){}
T* operator->() const
{
return pointee;
}
T& operator*() const
{
return *pointee;
}
// Member Function Templates
template<class newType>
operator SmartPtr<newType>()
{
return SmartPtr<newType>(pointee);
}
private:
T* pointee;
}; |
之后就可以正常編譯和運(yùn)行了。看起來(lái)很神奇吧,看看《More Effective C++》對(duì)此的解釋?zhuān)?br />現(xiàn)在請(qǐng)你注意,這可不是魔術(shù)——不過(guò)也很接近于魔術(shù)。假設(shè)編譯器有一個(gè)指向 T 對(duì)象的智能指針,它要把這個(gè)對(duì)象轉(zhuǎn)換成指向“T 的基類(lèi)”的智能指針。編譯器首先檢查 SmartPtr的類(lèi)定義,看其有沒(méi)有聲明明確的類(lèi)型轉(zhuǎn)換符,但是它沒(méi)有聲明。編譯器然后檢查是否存在一個(gè)成員函數(shù)模板,并可以被實(shí)例化成它所期望的類(lèi)型轉(zhuǎn)換。它發(fā)現(xiàn)了一個(gè)這樣的模板(帶有形式類(lèi)型參數(shù) newType) ,所以它把newType綁定成 T 的基類(lèi)類(lèi)型來(lái)實(shí)例化模板。 這時(shí),惟一的問(wèn)題是實(shí)例化的成員函數(shù)代碼能否被編譯:傳遞指針 pointee 到指向“T 的基類(lèi)”的智能指針的構(gòu)造函數(shù),必須合法的。指針pointee 是指向 T 類(lèi)型的,把它轉(zhuǎn)變成指向其基類(lèi)(public 或 protected)對(duì)象的指針必然是合法的,因此類(lèi)型轉(zhuǎn)換操作符能夠被編譯,可以成功地把指向 T 的智能指針隱式地類(lèi)型轉(zhuǎn)換為指向“T 的基類(lèi)”的智能指針。
附注:
1. Member Function Templates是C++的一個(gè)新特性,可能有些編譯器并不支持這個(gè)特性,比如VC6,編譯時(shí)似乎完全忽略了我們新加入的Member Function Templates代碼。仍然會(huì)提示如下錯(cuò)誤:
--------------------Configuration: MftDemo - Win32 Debug--------------------
Compiling...
MemFunTmp.cpp
g:\w7documents\visual studio 6.0\projects\mftdemo\memfuntmp.cpp(87) : error C2664: 'displayAndPlay' :
cannot convert parameter 1 from 'class SmartPtr<class CD>' to 'const class SmartPtr<class MusicProduct> &'
Reason: cannot convert from 'class SmartPtr<class CD>' to 'const class SmartPtr<class MusicProduct>'
No constructor could take the source type, or constructor overload resolution was ambiguous
g:\w7documents\visual studio 6.0\projects\mftdemo\memfuntmp.cpp(88) : error C2664: 'displayAndPlay' :
cannot convert parameter 1 from 'class SmartPtr<class MP3>' to 'const class SmartPtr<class MusicProduct> &'
Reason: cannot convert from 'class SmartPtr<class MP3>' to 'const class SmartPtr<class MusicProduct>'
No constructor could take the source type, or constructor overload resolution was ambiguous
執(zhí)行 cl.exe 時(shí)出錯(cuò).
MftDemo.exe - 1 error(s), 0 warning(s)
2. MS關(guān)于Member Function Templates的更多一些介紹
http://msdn.microsoft.com/en-us/library/swta9c6e.aspx
3. 本文的完整源代碼下載
Member Function Templates
原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明:
本文出自程序人生 >> Member Function Templates(成員函數(shù)模板)
作者:代碼瘋子