LoveBeyond

Member Function Templates(成员函数模板)

(本文最初发表于程序人生 >> 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(成员函数模板)
作者:代码疯子

posted on 2011-09-28 18:27 LoveBeyond 阅读(2112) 评论(0)  编辑 收藏 引用 所属分类: 杂乱无章

<2011年9月>
28293031123
45678910
11121314151617
18192021222324
2526272829301
2345678

导航

统计

留言簿(1)

文章分类

搜索

积分与排名

最新评论

阅读排行榜

评论排行榜

友情链接:C++博客 LoveBeyond 代码疯子 程序人生 C++技术博客