第六章-template模板
函数模板
函数模板可以用来创建一个通用功能的函数,以支持多种不同形参,进一步简化重载函数的函数体设计
函数定义的一般形式:
template <模板参数表>
类型名 函数名(参数表)
{
函数体定义
}
模板参数表由用逗号分隔的模板参数构成,用 class
或者 typename
来指明可以接受一个类型参数
template <typename T> //这里也可以写成 template <class T>
T abs(T x)
{
return x < 0 ? -x : x;
}
int main(){
int n=-5;
double m=-3.3;
cout<<abs(n)<<endl;
cout<<abs(m)<<endl;
return 0;
}
/*
程序运行的结果为:
5
3.3
*/
类型参数的含义确定后,编译器以函数模板为样板,生成一个函数,这一过程称为函数模板的实例化,该函数称为函数模板的一个实例
如果调用 abs函数时传入的参数为int,则运行时会生成一个int类型的实例函数,如果传入参数为double,则生成double类型的实例函数
细节:
- 函数模板在编译时不会产生目标代码,只有模板生成的实例才会产生目标代码
- 函数指针不能指向模板本身,只能指向模板的实例
- 被多个源文件引用的函数模板,应该把函数体一起写在头文件中
类模板
使用类模板可以让用户定义类的一种模式,使类中某些数据成员、某些函数成员的参数、返回值或局部变量能取任意类型
类模板需要一种或多种类型参数,因此也可以叫做参数化类
类模板声明的语法形式:
template <模板参数表>
class 类名
{
类成员声明
}
//模板参数表形式和函数模板的一样
//类成员声明方法和普通类的定义相同,只是它的各个成员可以使用模板类型中的参数T
如果需要在类模板以外定义其成员函数,采用以下形式:
template <模板参数表>
类型名 类名<模板参数标识符列表>::函数名(参数表)
使用一个模板类来建立对象时,采用以下形式:
模板名<模板参数表>对象名1,···,对象名N;
template<class T> //类模板,实现对任意类型的数据进行存取
class Store{
public:
Store(){
haveValue=false; //默认为 false
}
T &getElem(); //提取数据函数
void putElem(T x); //存入数据函数
private:
T item; //item用于存放任意类型的数据
bool haveValue; //haveValue用来判断 item是否存取
};
template<class T>
T &Store<T>::getElem(){
if(!haveValue){ //如果试图提取未初始化的数据,则终止程序
cout<<"NO item present!"<<endl;
exit(1);
}
return item; //提取成功,则返回item中存取的数据
}
template<class T>
void Store<T>::putElem(T x){
item=x;
haveValue=true; //表示item中已经存入数据
}
int main(){
Store<int>s1,s2; //定义两个Store<int>对象
s1.putElem(3);
s2.putElem(-7);
cout<<s1.getElem()<<" "<<s2.getElem()<<endl;
Store<double>s3,s4; //定义两个Store<double>对象
s3.putElem(4.3);
s4.putElem(-9.2);
cout<<s3.getElem()<<" "<<s4.getElem()<<endl;
Store<int>s5;
cout<<s5.getElem()<<endl; //数据没有初始化,进行异常处理
return 0;
}
/*
程序运行的结果为:
3 -7
4.3 -9.2
NO item present!
*/
一个类模板声明自身并不是一个类,而是说明了类的一个家族。只有被其他代码引用时,模板才根据引用的需要生成具体的类