泛型编程
泛型编程独立于任何特定的数据类型,使得不同类型的数据可以被相同的代码操作。泛型编程在编译时有多态性,数据类型本身是参数化的,编译时编译器将实现代码的实例化
在c++中使用模版进行泛型编程
模版有函数模版和类模版两种
函数模版
template <模版形参表>
返回值类型 函数名 (形参列表){
函数体语句
}
其中模版形参表不能为空,形参列表必须包含模版形参表中出现的所有形参
template <typename T>
void Swap(T & v1, T & v2){
T temp;
temp = v1;
v1 = v2;
v2 = temp;
}
模版形参可以有多个
template <typename T, typename D, ...>
函数模版的使用形式与普通函数调用相同。
编译器会根据函数中调用所给出的实参类型确定模版实参,然后用模版实参代替模版形参产生并编译函数模版(实例化)。注意的是此过程中不进行常规隐式类型转换
显示模版特化
想对特殊类型进行一些特殊操作可以用模版特化
template <>
void Swap(int & v1, int & v2){
int temp;
temp = v1;
v1 = v2;
v2 = temp;
}
当传入的类型是int就会执行模版的特化部分,而非int类型执行正常的模版推断
模版重载
和函数重载一样,我们可以定义名字相同而函数形参表不同的函数模版,或者定义与函数模版同名的非模版函数,实现模版的重载
当进行重载时,编译器调用顺序:
- 如果有非模版函数的形参类型与调用的是实参类型完全一致,则调用该函数
- 看模版函数的特化是否符合调用的实参,符合则调用该函数
- 看非特化的模版函数是否能实例化后与调用的实参类型完全一致,有则调用该函数
- 对调用的实参进行隐式转换后再与非模版函数进行匹配,若可以则调用该函数
- 编译错误
类模版
//类模版一般形式
template <模版形参表>
class 类名 {
类成员声明
};
//类模版外定义成员函数的一般形式
template <模版形参表>
返回值类型 类名<模版形参名列表>::函数名(函数形参表) {
函数实现
};
注意区分模版形参表和模版形参名列表
模版形参表
<typename T, typename D, ...>
模版形参名列表
<T, D, ...>
类模版实例化的形式为
类模版名 <模版实参表>
非类型模版形参
非类型模版形参是模版内部的常量,类似于普通函数的形参,编译时由对应的模版实参值代替,对应的模版实参必须是常量表达式
template <typename T, int N>
class stack{
...
private:
T a[N];
}
//使用时
stack<int , 10> a;
模版中的友元函数
//模版中的友元函数要这样定义
template<typename D>
friend ostream& operator<<(ostream& out, Counter<D>& f);
类中用的是T,这里用的是D,即两者不能用同一个字母
//类外实现
template<typename T>
ostream& operator<<(ostream& out, Counter<T>& f){
...
}
与非模版友元类的区别就是在前面要加上template<typename T>,传入的类要加上<T>