C++提供的模板机制提高了代码的复用性,C++模板分为函数模板和类模板;
一、函数模板
定义:template<class T>
返回值类型 函数名 (参数列表) {
//函数体
}
template是关键字,表明是模板定义,后面<class T>是模板参数列表,它给出数据类型参数T,也就是说这里的class不是我们之前认识的类class,它表示后面跟的是模板参数;
二、区别俩个术语——函数模板和模板函数
函数模板:一类函数的抽象,就是说带类型参数的函数,比如:它是一类函数的集合,根据类型参数而定执行函数体,也可以说是类型参数未实列化之前的函数; template<class T>
void Swap(T &a,T&b)
{
T c = a;a =b;b =c;
}
模板函数:类型参数被实列化之后的函数,就如Swap函数,编译器调用Swap()时,根据实参的类型推导出函数模板的类型参数,当类型参数确定之后,编译器将以函数模板为样板,生成一个函数:,这个函数就叫做模板函数,他是有函数模板产生的; void Swap(int &a,int &b)
{
int c = a;a =b;b=c;
}
三、函数模板和它同名重载函数的匹配顺序
总结了一下几条规则:
1、先匹配重载函数,如果参数完全匹配(一定是完全),则调用重载函数;
2、如果重载函数的参数列表不匹配,则就去匹配函数模板,根据实列化后的具体参数推到出函数模板的参数列表,如果匹配成功就去调用,函数模板生成的模板函数;
3、如果以上俩条都不成立,编译器会通过类型转化,来检验调用是否和重载函数匹配,如果是则调用重载函数;
4、如果上述三条都没找到匹配的函数,那么编译器会给出调试错误信息;
以下是测试代码:
#include<iostream>
using namespace std;
template <class T>
void Swap(T &a,T&b)
{
cout<<"T"<<endl;
T c= a;
a =b;
b =c;
}
template <class T>
void Swap(T *a,T*b)
{
cout<<"T"<<endl;
T c= *a;
*a =*b;
*b =c;
}
void Swap(float* a,float* b)
{
cout<<"float*"<<endl;
float c = *a;
*a=*b;
*b=c;
}
int main()
{
float i = 10.0, j =20;
int m =10,n=20;
Swap(m,n);
Swap(&i,&j);//有重载函数,先会匹配重载函数
Swap(&m,&n);//无重载函数就会使用函数模板
cout <<"i = "<<i<<"j = "<<j<<endl;
cout <<"m = "<<m<<"n = "<<n<<endl;
}
根据需要函数模板的参数可以有多个;
另外说明一点:如果你用template<class T>然后却用具体参数去声明一个还是函数:void Swap(int &a,int&b),这样编译器会报错;四、类模板和函数模板的用法都一样
typename 与 class 的区别:
<1>相同点:
类模板声明有俩中:
template<class T> || template<typename T>;
在这里声明一个类模板时,class 和 typename 是完全一样的,都表示模板的参数类型;
<2>不同点:
c++中typename有一个特别的用处:关键字typename被用来作为型别之前的标识符;
class Q { public: typedef int SubType;
typename Seqlist<T>::reference Seqlist<T>:: operator[](int pos)template<class T> class Seqlist { public: typedef T& reference; reference operator[](int pos); };
{
.....
}
typename的功能就像是限定,(或者是给定更合适)某个已经定义的标识符作用域的,好让编译器能够知道这个标识的来自哪里;