目录
一、泛型编程
来看看下面这段代码
int Max(int a, int b)
{
return a > b ? a : b;
}
char Max(char a, char b)
{
return a > b ? a : b;
}
double Max(double a, double b)
{
return a > b ? a : b;
}
short Max(short a, short b)
{
return a > b ? a : b;
}
void main()
{
cout << Max(10, 20) << endl; //20
cout << Max('A', 'B') << endl; //'B'
cout << Max(10.23, 2.45) << endl; //10.23
}
共有三个Max函数,内部执行的功能都是一样的求较大值,但就是参数类型不同,我们在求不同类型的时候,就要分别写出其对应的函数,这个时候就是很麻烦,代码冗杂度太大了,
那么我们就会思考,能不能写一个万能的通用代码,不管什么类型的参数,都能去实现Max功能呢?(就像流水线生成的时候,机械化的进行一些步骤,我们只需要在进行一点小小的操作就能变成不同的产品)
模板就能解决这样的问题
1、模板的概念
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定 类型版本。
2、模板的格式
template<Typename Type1,Typename Type2,Typename Type3>
返回值类型 函数名 (参数列表)
{
//实现的具体代码
}
实现Max的代码为:
template<typename Type>
Type Max(Type a, Type b)
{
return a > b ? a : b;
}
二、函数模板的使用
普通内置类型:
类类型:需要使用重载
直接调用的话可以看到是运行不了的,是因为在比较大小的时候,编译器并不知道类类型到底要怎么进行 > 的比较
为了让编译器能够知道怎样进行比较,这时候我们就需要进行重载。我们对 > 进行重载
重载如下,这个const是因为要进行类型的匹配,定义模板的时候类型是家里const
bool operator>(const Test& t)const
{
return m_data > t.m_data ? m_data : t.m_data;
}
三、函数模板的本质
函数模板是一个蓝图,它本身并不是函数,是编译器使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器
三、类模板的使用
之前在数据结果的时候,只能定义单个类型的顺序表,
当使用了模板以后,就可以定义多种不同类型的顺序表
需要注意的是,当定义类函数的时候,在类外部实现函数的时候格式是需要注意的,不光要加上类的限定,还有在前面加上模板信息
非类型的模板参数:
模板中的参数不一定要存储类型,
注意:
1、这里的yourlist和herlist只有一个参数是因为模板里面的第二个参数已经有了默认值,这时候可把第二个参数给省略了,
但如果没有默认值,那么就必须要写两个参数才行
2、非类型的模板参数只能是整形的,float,double等都不行
零初始化:
”用一个有用的缺省值来对他们进行初始化“的缺省构造函数,相反,任何未被初始化的局部变量都具有一个不确定的值
可以看到,这时候,定义的局部变量都有一个随机的值
可以通过零初始化的方法对变量进行赋“零值”,但这里的零值并不是真的0,而是根据参数的类型进行转换的,
int 对应 0 , bool 对应 false 等
同样的,对于模板类,也可以通过零初始化的方法
四、模板的特化
函数模板的特化
- 概念:
- 我们的模板是可以解决绝大多数问题的,但是在一些特殊的情况下有一些问题无法用通用的模板解决,这时我们就需要将模板特化,用来解决特殊情况下的问题。例如下面的情况:
这里我们是想比较两个字符串的大小,但是我们这里传入的是两个指针,那么到时候在比较时,比较的是指针中保存的地址的大小,而不是字符串的大小,这里我们就需要对模板进行特化
类模板的全特化
类模板的偏特化
还可以进一步进行条将限制设计的特化版本