(本文最初发表于程序人生 >> Member Function Templates(成员函数模板) 作者:代码疯子)Member Function Templates翻译成中文就是成员函数模板,这个东西我个人见得少,最初是在STL的auto_ptr源代码里面看到的,当时候也不是很明白;这几天又翻了翻《More Effective C++》,正好看到上面介绍的比较详细,就找了点资料总结一下。
为了更好的说明问题,我们自己定义一个Smart Pointer(智能指针,这里只是示例,所以定义是不完整和不完善的),假设现在我们手上有这样三个类:MusicProduct、CD、MP3,类之间的关系图如下:
我们定义的智能指针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;
}; |
现在有一个播放函数:
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();
}
} |
如果有下面这样的调用,会不会有什么问题呢?
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;
} |
实际编译时会发生错误,在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的定义中增加成员函数模板实现代码,具体如下:
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;
}; |
之后就可以正常编译和运行了。看起来很神奇吧,看看《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)
2. MS关于Member Function Templates的更多一些介绍
http://msdn.microsoft.com/en-us/library/swta9c6e.aspx
3. 本文的完整源代码下载
Member Function Templates
原创文章,转载请注明:
本文出自程序人生 >> Member Function Templates(成员函数模板)
作者:代码疯子