这一篇主要是总结c++模板。
函数模板针对仅参数类型不同的函数;
类模板针对仅数据成员和成员函数类型不同的类。
模板产生的背景
使用模板的目的就是能够让程序员编写与类型无关的代码。
比如编写了一个交换两个整型int 类型的swap函数,这个函数就只能实现int 型,对double,字符这些类型无法实现,要实现这些类型的交换就要重新编写另一个swap函数。使用模板的目的就是要让这程序的实现与类型无关,比如一个swap模板函数,即可以实现int 型,又可以实现double型的交换。模板可以应用于函数和类。
模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板。
函数模板
template <class 形参名,class 形参名,......> 返回类型 函数名(参数列表)
{
函数体
}
template和class是关键字,class可以用typename 关键字代替,在这里typename 和class没区别,<>括号中的参数叫模板形参,模板形参和函数形参很相像,模板形参不能为空。
示例: template void swap(T& a, T& b){}
使用示例
对于函数模板而言不存在 h(int,int) 这样的调用,不能在函数调用的参数中指定模板形参的类型,对函数模板的调用应使用实参推演来进行,即只能进行 h(2,3) 这样的调用,或者int a, b; h(a,b)。
template<typename T>
int compare(const T& left, const T& right) {
if (left < right) {
return -1;
}
if (right < left) {
return 1;
}
return 0;
}
compare<int>(1, 2); //使用模板函数
compare<double>(1.0, 2.0); //使用模板函数
类模板
template<class 形参名,class 形参名,…> class 类名
{ ... };
类模板和函数模板都是以template开始后接模板形参列表组成,模板形参不能为空
示例:template class A{public: T a; T b; T hy(T c, T &d);};
在类模板外部定义成员函数
template<模板形参列表> 函数返回类型 类名<模板形参名>::函数名(参数列表){函数体},
示例:template<class T1,class T2> void A<T1,T2>::h(){}。
当在类外面定义类的成员时template后面的模板形参应与要定义的类的模板形参一致。
使用示例
使用类模板创建对象的方法为 A m;在类A后面跟上一个<>尖括号并在里面填上相应的类型,这样的话类A中凡是用到模板形参的地方都会被int 所代替。当类模板有两个模板形参时创建对象的方法为A<int, double> m; 类型之间用逗号隔开。
类模板形参不存在实参推演的问题。也就是说不能把整型值2推演为int 型传递给模板形参。要把类模板形参调置为int 型必须这样指定A m。
template<class T,int MAXSIZE> class Stack{//MAXSIZE由用户创建对象时自行设置
private:
T elems[MAXSIZE]; // 包含元素的数组
int numElems; // 元素的当前总个数
public:
Stack(); //构造函数
void push(T const&); //压入元素
void pop(); //弹出元素
};
template <class T,int MAXSIZE>
Stack<T,MAXSIZE>::Stack():numElems(0){ // 初始时栈不含元素
// 不做任何事情
}
template <class T,int MAXSIZE>
void Stack<T, MAXSIZE>::push(T const& elem){
if(numElems == MAXSIZE){
throw std::out_of_range("Stack<>::push(): stack is full");
}
elems[numElems] = elem; // 附加元素
++numElems; // 增加元素的个数
}
template<class T,int MAXSIZE>
void Stack<T,MAXSIZE>::pop(){
if (numElems <= 0) {
throw std::out_of_range("Stack<>::pop(): empty stack");
}
--numElems; // 减少元素的个数
}
Stack<int,20> int20Stack; // 可以存储20个int元素的栈
Stack<std::string,40> stringStack; // 可存储40个string元素的栈
int20Stack.push(7);
stringStack.push("hello");
默认模板类型形参
类模板类型形参默认值和函数的默认参数一样,如果有多个类型形参则从第一个形参设定了默认值之后的所有模板形参都要设定默认值.
在类模板的外部定义类中的成员时template 后的形参表应省略默认的形参类型。
比如template<class T1, class T2=int> class A{public: void h();};
定义方法为template<class T1,class T2> void A<T1,T2>::h(){}。
template<class T1, class T2=int> class A{};为第二个模板类型形参T2提供int型的默认值。
使用示例
//定义带默认类型形参的类模板。这里把T2默认设置为int型。
template<class T1,class T2=int> class CeilDemo{
public:
int ceil(T1,T2);
};
//在类模板的外部定义类中的成员时template 后的形参表应省略默认的形参类型。
template<class T1,class T2>
int CeilDemo<T1,T2>::ceil(T1 a,T2 b){
return a>>b;
}
CeilDemo<int> cd;
cd.ceil(8,2);