1.
泛型编程
如何实现一个通用的交换函数呢?
void
Swap
(
int
&
left
,
int
&
right
)
{
int
temp
=
left
;
left
=
right
;
right
=
temp
;
}
void
Swap
(
double
&
left
,
double
&
right
)
{
double
temp
=
left
;
left
=
right
;
right
=
temp
;
}
void
Swap
(
char
&
left
,
char
&
right
)
{
char
temp
=
left
;
left
=
right
;
right
=
temp
;
}
使用函数重载虽然可以实现,但是有一下几个不好的地方:
1.
重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数
2.
代码的可维护性比较低,一个出错可能所有的重载均出错
那能否
告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码
呢?
2.
函数模板
2.1
函数模板概念
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定
类型版本。
2.1
函数模板格式
template<typename T1, typename T2,......,typename Tn>
返回值类型 函数名
(
参数列表
){}
template
<
typename
T
>
void
Swap
(
T
&
left
,
T
&
right
)
{
T temp
=
left
;
left
=
right
;
right
=
temp
;
}
注意:
typename
是
用来定义模板参数
关键字
,
也可以使用
class(
切记:不能使用
struct
代替
class)
2.3
函数模板的原理
函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模
板就是将本来应该我们做的重复的事情交给了编译器
在编译器编译阶段
,对于模板函数的使用,
编译器需要根据传入的实参类型来推演生成对应类型的函数
以供调用。比如:当用
double
类型使用函数模板时,编译器通过对实参类型的推演,将
T
确定为
double
类型,然
后产生一份专门处理
double
类型的代码
,对于字符类型也是如此。
2.4
函数模板的实例化
用不同类型的参数使用函数模板时
,称为函数模板的
实例化
。模板参数实例化分为:
隐式实例化和显式实例
化
。
1.
隐式实例化:让编译器根据实参推演模板参数的实际类型
2.
显式实例化:在函数名后的
<>
中指定模板参数的实际类型
如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。
2.5
模板参数的匹配原则
1.
一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函
数
2.
对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模
板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板
3.
模板函数不允许自动类型转换,但普通函数可以进行自动类型转换
3.
类模板
3.1
类模板的定义格式
template
<
class
T1
,
class
T2
, ...,
class
Tn
>
class
类模板名
{
//
类内成员定义
};
//
动态顺序表
//
注意:
Vector
不是具体的类,是编译器根据被实例化的类型生成具体类的模具
template
<
class
T
>
class
Vector
{
public
:
Vector
(
size_t
capacity
=
10
)
:
_pData
(
new
T
[
capacity
])
,
_size
(
0
)
,
_capacity
(
capacity
)
{}
//
使用析构函数演示:在类中声明,在类外定义。
~Vector
();
void
PushBack
(
const
T
&
data
)
;
void
PopBack
()
;
// ...
size_t
Size
() {
return
_size
;}
T
&
operator
[](
size_t
pos
)
{
assert
(
pos
<
_size
);
return
_pData
[
pos
];
}
private
:
T
*
_pData
;
size_t
_size
;
size_t
_capacity
;
};
//
注意:类模板中函数放在类外进行定义时,需要加模板参数列表
template
<
class
T
>
Vector
<
T
>
::
~Vector
()
{
if
(
_pData
)
delete
[]
_pData
;
_size
=
_capacity
=
0
;
}
3.2
类模板的实例化
类模板实例化与函数模板实例化不同,
类模板实例化需要在类模板名字后跟
<>
,然后将实例化的类型放在
<>
中即可,类模板名字不是真正的类,而实例化的结果才是真正的类
// Vector
类名,
Vector<int>
才是类型
Vector
<
int
>
s1
;
Vector
<
double
>
s2
;