模板是一种源码复用技术,在某些情况下使用它可以使代码看起来非常优雅,著名的boost库就是模板发扬的典范.
然而模板也存在弊端,大量使用模板可能导致代码膨胀.下面介绍一种解决的方案:
我们首先看一段一般代码:
template
<
typename T
>
class
Vector
{
public
:
virtual
void
Say()
{
const
type_info
&
t
=
typeid(T);
std::cout
<<
"
Vector<
"
<<
t.name()
<<
"
>::Hello
"
<<
std::endl;
}
}
;
//
特例化
template
<>
class
Vector
<
void
*>
{
public
:
virtual
void
Say()
{
std::cout
<<
"
Vector<void*>::Hello
"
<<
std::endl;
}
}
;
int
_tmain(
int
argc, _TCHAR
*
argv[])
{
Vector
<
int
*>
pIntVec;
pIntVec.Say();
Vector
<
double
*>
pDoubleVec;
pDoubleVec.Say();
return
0
;
}
输出:
Vector<int *>::Hello
Vector<double *>::Hello
从这里,我们可以看出程序在运行的过程中生产了两分Vector的代码(int*和double*),尽管这里有特例化,然而类型不匹配,编译器在编译过程中无法定位到特例化版本.如果这个Vector被滥用的化,我想即使是一个中等规模的程序也可能耗费成兆字节的代码控件.
我们必须寻找一种中间桥梁使编译器在编译过程中定位到void*的特例化版本.按照模板选择策略,编译器总是选择最特例化的模板,我们可以通过一个中间的模板联系起上面两个版本的模板.下面看一段代码:
template
<
typename T
>
class
Vector
{
public
:
virtual
void
Say()
{
std::cout
<<
"
Vector::Hello
"
<<
std::endl;
}
}
;
//
特例化
template
<>
class
Vector
<
void
*>
{
public
:
virtual
void
Say()
{
std::cout
<<
"
Vector<void*>::Hello
"
<<
std::endl;
}
}
;
//
特例化
template
<
typename T
>
class
Vector
<
T
*>
:
public
Vector
<
void
*>
{
}
;
int
_tmain(
int
argc, _TCHAR
*
argv[])
{
Vector
<
int
*>
pIntVec;
pIntVec.Say();
Vector
<
double
*>
pDoubleVec;
pDoubleVec.Say();
return
0
;
}
输出:
Vector<void*>::Hello
Vector<void*>::Hello
从这里,我们可以看出程序在运行过程中全部使用Vector<void*>的版本.class Vector<T*>模板便是关键的环节.编译器在编译过程中,由于class Vector<T*>比class Vector更特例化,所以遇到Vector<int*>和Vector<double*>时都选择class Vector<T*>,而class Vector<T*>继承Vector<void*>,一个更加特例化版本,所以编译器不再产生新的模板而采用Vector<void*>这个最特例化版本,这样所有指针模板都归结到Vector<void*>,而class Vector<T*>为用户提供了一个精美而且安全的界面,而Vector<void*>作为底层实现细节被隐藏.
以上代码在VC 7.1(VS2003)中编译通过,由于VC6对模板支持不好,所以模板的高级用法一般不要在VC6中使用.
下载演示代码
posted on 2006-03-27 18:54
万连文 阅读(2313)
评论(7) 编辑 收藏 引用 所属分类:
模板