当前位置:编程学习 > C/C++ >>

Member Function Templates(成员函数模板)

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”
 

补充:软件开发 , C语言 ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,