程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> 關於C >> Member Function Templates(成員函數模板)

Member Function Templates(成員函數模板)

編輯:關於C

Member Function Templates翻譯成中文就是成員函數模板,這個東西我個人見得少,最初是在STL的auto_ptr源代碼裡面看到的,當時候也不是很明白;這幾天又翻了翻《More Effective C++》,正好看到上面介紹的比較詳細,就找了點資料總結一下。
為了更好的說明問題,我們自己定義一個Smart Pointer(智能指針,這裡只是示例,所以定義是不完整和不完善的),假設現在我們手上有這樣三個類:MusicProduct、CD、MP3,類之間的關系圖如下:

類圖
我們定義的智能指針SmartPtr如下:

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;
};
 

現在有一個播放函數:

void displayAndPlay(const SmartPtr<MusicProduct>& pmp, int times)
{
 for (int i = 1; i <= times; ++i)
 {
  pmp->displayTitle();
  pmp->play();
 }
}
如果有下面這樣的調用,會不會有什麼問題呢?

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;
}
 

實際編譯時會發生錯誤,在Visual Studio 2008下面提示如下錯誤:

1>error C2664: “displayAndPlay”: 不能將參數 1 從“SmartPtr<T>”轉換為“const SmartPtr<T> &”
1>        with
1>        [
1>            T=CD
1>        ]
1>        and
1>        [
1>            T=MusicProduct
1>        ]
1>        ......
提示“SmartPtr”不能轉換為“const SmartPtr &” 。因為在編譯器眼裡SmartPtr和SmartPtr是兩個完全不相關的東西,他們之間沒有繼承關系。我們可以寫一個隱式類型轉換,但實際操作起來不太理想,正如前面所說,STL的auto_ptr采用了Member
 

Function Templates(成員函數模板)技術。我們可以再SmartPtr的定義中增加成員函數模板實現代碼,具體如下:

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;
};
之後就可以正常編譯和運行了。看起來很神奇吧,看看《More Effective C++》對此的解釋:
現在請你注意,這可不是魔術——不過也很接近於魔術。假設編譯器有一個指向 T 對象的智能指針,它要把這個對象轉換成指向“T 的基類”的智能指針。編譯器首先檢查 SmartPtr的類定義,看其有沒有聲明明確的類型轉換符,但是它沒有聲明。編譯器然後檢查是否存在一個成員函數模板,並可以被實例化成它所期望的類型轉換。它發現了一個這樣的模板(帶有形式類型參數 newType) ,所以它把newType綁定成 T 的基類類型來實例化模板。 這時,惟一的問題是實例化的成員函數代碼能否被編譯:傳遞指針 pointee 到指向“T 的基類”的智能指針的構造函數,必須合法的。指針pointee 是指向 T 類型的,把它轉變成指向其基類(public 或 protected)對象的指針必然是合法的,因此類型轉換操作符能夠被編譯,可以成功地把指向 T 的智能指針隱式地類型轉換為指向“T 的基類”的智能指針。
附注:
1. Member Function Templates是C++的一個新特性,可能有些編譯器並不支持這個特性,比如VC6,編譯時似乎完全忽略了我們新加入的Member Function Templates代碼。仍然會提示如下錯誤:
--------------------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
執行 cl.exe 時出錯.
 
MftDemo.exe - 1 error(s), 0 warning(s)

 作者“LoveBeyond”
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved