首先我们来明确函数模板与类模板的概念及其用法。
模板是一种对类型进行参数化的工具,通常有两种形式------>函数模板和类模板。
函数模板针对仅参数类型不同的函数;
类模板针对仅数据成员和成员函数类型不同的类。
函数模板的格式:
template <class 形参名,class 形参名,......> 返回类型 函数名(参数列表)
{
函数体
}
(1)template和class是关键字,class可以用typename关键字代替,在这里typename 和class没区别。
(2)<>括号中的参数叫模板形参,模板形参和函数形参很相像,模板形参不能为空。一但声明了模板函数就可以用模板函数的形参名声明类中的成员变量和成员函数,即可以在该函数中使用内置类型的地方都可以使用模板形参名。模板形参需要调用该模板函数时提供的模板实参来初始化模板形参,一旦编译器确定了实际的模板实参类型就称实例化了函数模板的一个实例。
比如swap的模板函数形式为
template <class T>
void swap(T &a, T &b)
{
}
类模板的格式:
template<class 形参名,class 形参名,…> class 类名
{ ... };
类模板和函数模板都是以template开始后接模板形参列表组成,模板形参不能为空,一但声明了类模板就可以用类模板的形参名声明类中的成员变量和成员函数,即可以在类中使用内置类型的地方都可以使用模板形参名来声明。比如
template<class T>
class A
{
public:
T hy(T c, T &d);
};
在类A中声明了一个返回类型为T带两个参数类型为T的函数hy。
注意的是:
(1)模板函数没有默认的类型转换
(2)普通函数与函数模板一同存在,会优先调用普通函数
(3)模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行,比如不能在main函数中声明 或定义一个模板。
(4)在运行过程中,如果不加显示调用,有时就会编译出错
举例:
template < typename T > //函数模板
void print( T x , T y ) //模板函数没有默认的类型转换
{
cout<< "模板函数" <<endl;
cout<< x << " " << y <<endl;
}
void print(int x,int y) //普通函数有默认的类型转换 且只有char型和int型可以自由转换
{
cout<< "普通函数" <<endl;
cout<< x << " " << y <<endl;
}
在main函数中调用时出现如下代码
//普通函数与函数模板一同存在,会优先调用普通函数
print(1,2); //隐式调用
print<int>(1,2); //显式调用
print(1,'a'); //只能调用普通函数实现 如果注释掉普通函数,仅仅调用模板函数就会出错
冒泡函数
//用冒泡排序 稳定算法
#include<iostream>
using namespace std;
template <typename T>
void get(T *a,int len) //实现数组内容输入
{
for(int i=0;i<len;i++)
{
cin >> a[i];
}
}
template <typename T>
void Bubble_sort(T *a,int len) //进行排序
{
T tmp;
for(int i=1;i<=len-1;i++) //最后一个不需要比较
{
for(int j=0;j<=len-1-i;j++)
{
if(a[j]>a[j+1])
{
tmp = a[j];
a[j] = a[j+1];
a[j+1] = tmp;
}
}
}
}
template <typename T>
void print(T *a,int len) //实现数组内容输出
{
for(int i=0;i<len;i++)
{
cout<< a[i] << " ";
}
cout<<endl;
}
int main()
{
int len=10;
/*
int a[20]={0};
get<int>(a,len); //定义T为int型 输出int型
Bubble_sort<int>(a,len); //显示调用
print<int>(a,len);
*/
char a[20]="jquaisahsqwuqidshd";
Bubble_sort<char>(a, sizeof(a)/sizeof(a[0]) ); //定义T为char型 输出char型
print<char>(a,sizeof(a)/sizeof(a[0]));
return 0;
}