文章目录
泛型编程 – 模版
引子
在此前的学习中,我们知道了 C++ 运用函数重载,使得以下代码能够正常运行
//C语言没有重载的概念,自然不会允许同名函数的出现,编译器会报错
//C++ 一切正常
void Swap(int* x, int* y) { //只在 C++ 里实现时肯定是用引用更好
int tmp = *x;
*x = *y;
*y = tmp;
}
void Swap(double* x, double* y) {
double tmp = *x;
*x = *y;
*y = tmp;
}
int main() {
int a = 1, b = 2;
Swap(&a, &b);
printf("%d %d\n", a, b);
double c = 3.1, d = 4.1;
Swap(&c, &d);
printf("%f %f\n", c, d);
return 0;
}
但即便如此,每多一种类型的交换就要多重载一次函数,显然还是太过麻烦,于是有了 模板
模板格式
//template<typename T> //也可以这么写,都是一样的
template<class T> //只说明下面的Swap函数是个模版
void Swap(T& x, T& y) {
T tmp = x;
x = y;
y = tmp;
}
int main() {
int a = 1, b = 2;
Swap(a, b);
double c = 3.1, d = 4.1;
Swap(c, d);
}
模版原理
● 编译器根据传入的参数类型,将模板实例化为相应的函数
—— 把反复重载函数的工作交给编译器去做了
可知,以上代码中 Swap(a, b) 与 Swap(c, d) 调用的不是同一个函数
注意
- 模版的歧义 – 显式实例化学习
template<class T>
T Add(const T& x, const T& y) {
return x + y;
}
int main() {
int a = 1; double b = 2;
Add(a,b);//报错,因为模板会因为这两个不同类型的数据产生歧义
//解决方式 1:强制类型转化 让类型一致
Add((double)a, b);
//解决方式 2:显式实例化 主动指定T
Add<int>(a, b);
//解决方式 3:写两个模板参数
//………………………………………………………………………
return 0;
}
- 调用函数的优先级(了解即可)
// 专门处理int的加法函数
int Add(int left, int right)
{
return left + right;
}
// 通用加法函数
template<class T>
T Add(T left, T right)
{
return left + right;
}
int main(){
int a = 1, b = 2;
Add(a, b); //调用第一个函数 —— 方便,何乐而不为
Add<int>(a, b); //就是想用模板
}
其他
举例归举例,库里其实有 swap 函数,以后用这个就行:
类模版
根据以前所学,想要以下的 Satck 创建的变量即有能存放 int 类型的,又有能存放 double 类型的显然不太现实:
typedef double STDataType;
class Stack
{
private:
STDataType* _a;
size_t _top;
size_t _capacity;
};
于是就有了 类模版:
template<class T>
class Stack
{
private:
T* _a;
size_t _top;
size_t _capacity;
};
int main()
{
Stack<int> st1; // int
Stack<double> st2; // double
}
显然,类模版只能显式实例化
类模版声明定义分离
//定义在类外:
template<class T> //声明模版参数
Stack<T>::~Stack() //加上模版参数
{
delete[] _a;
_capacity = _top = 0;
}
但因为一些原因,类模版声明定义分离不能分离到不同的文件里(会出现链接错误),只能在本文件中