目录
一、函数模板
二、类模板
一、函数模板
当我们没有使用到模板的时候,我们如果要交换两个数据,那么我们就要根据交换的数据的类型,写出例如以下的函数:
void Swap(int& a, int& b)
{int tmp = a;a = b;b = tmp;
}void Swap(double& a, double& b)
{double tmp = a;a = b;b = tmp;
}...
虽然通过函数重载可以实现我们想要的功能,但是非常的麻烦。C++中添加了模板的使用,这就解决了这个问题。
模板分为:函数模板和类模板。
函数模板代表了一个函数家族,该函数模板与类型无关,在使用的时候才被编译器实例化,编译器会根据传入的实参类型,生成对应版本的函数。
函数模板的基本格式为:
template <typename T1,typename T2 ......>
返回值 函数名(参数列表)
这里的typename还可以用class代替,效果是一样的。
template<class T>
void Swap(T& a, T& b)
{double tmp = a;a = b;b = tmp;
}int main()
{int x = 1, y = 2;double a = 1.1, b = 2.2;Swap(x, y);Swap(a, b);Swap(x, b);return 0;
}
这里的三次调用Swap函数前两次都是正确的,第三次则是错误的,因为这里我们定义的模板里只有一种类型,而我们传入的实参有两种类型,编译器不能识别我们到底是要用哪种类型的函数。
template<class T>
T Add(const T& a,const T& b)
{return a + b;
}int main()
{int x = 1, y = 2;double a = 1.1, b = 2.2;Add(x, y);Add(a, b);Add(x,b);return 0;
}
要解决这个问题的办法有两种,一是我们主动给对实参进行强制类型转化,但这个又会出现一个问题,类型转化后的结果是保存在一个临时变量中的,临时变量具有常性,我们形参的类型是T&,而实参是临时变量,被const修饰,所以传参的时候会发生权限的放大,还是会报错,我们要把形参也用const修饰上,才能保证形参和实参一致。
第二种方法就是显示的实例化:在函数名后加上<>指定模板的参数类型。这样函数模板就可以支持自动的隐式类型转化了。
同时非函数模板和函数模板可以同时存在,这个函数模板也可以实例化成这个非函数模板。当其他条件都相同时,在调用时会优先调用这个非函数模板,而不是通过函数模板去实例化。
还有一种情况必须显示的实例化:形参中没有涉及模板类型的,比如:
template<class T>
T* func(int n)
{return new T[n];
}
这种情况我们在使用这个函数的时候,模板类型和我们传入的参数无关,编译器没办法识别到我们想要实例化出什么类型,因此在调用这种函数模板时,必须显示的实例化。
二、类模板
类模板的用法和函数模版类似 ,但是有一点,类模板的声明和定义不建议分离到两个文件中,会出现链接错误。
template<class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};
当一个文件中的类模板的成员函数的声明的定义分离时,写法如下:
template<class T>
class Stack
{
public:Stack(int n = 4);
private:T* arr;int _size;int _capacity;
};//template只作用和他相连的一个类或者函数,在类外定义的时候要重新写一遍
//这里的变量名可以于类使用的变量名不同 因为它代表的仅是一种变量类型 没有实际意义
template<class T>
Stack<T>::Stack(int n)
{arr = new T[n];_size = 0;_capacity = n;
}
类模板的实例化和函数模板的实例化不同,类模板在实例化时,需要在类模板的名字后面加上<>,然后把需要实例化的类型放在<>中,类模板的名字不是真的类,实例化的结果才是一个真正的类。
template<class T>
class Stack
{
public:Stack(int n = 4);
private:T* arr;int _size;int _capacity;
};template<class T>
Stack<T>::Stack(int n)
{arr = new T[n];_size = 0;_capacity = n;
}int main()
{//这里的Stack<int> Stack<double>才是类型//Stack只是类名Stack<int> st1;Stack<double> st2;
}