模板——实现泛型编程的有力武器
- 我们为什么需要模板?
- 模板
前言:关于模板,相信大家都有所而闻,以下是我对C++模板的个人看法,希望能够帮助到你们呀!
我们为什么需要模板?
请到大家看这一段代码?
void Swap(int& left, int& right)
{int temp = left;left = right;right = temp;
}
void Swap(double& left, double& right)
{double temp = left;left = right;right = temp;
}
void Swap(char& left, char& right)
{char temp = left;left = right;right = temp;
}
我们发现这是实现left和right数值交换的Swep函数,这三段代码,区别仅仅在于数据类型的不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数,有没有什么办法解决类似的问题?这个时候,能否告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码呢?
模板
- 函数模板格式
template<typename T>
void Swap( T& left, T& right)
{T temp = left;left = right;right = temp;
}
注意:typename是用来定义模板参数关键字,也可以使用class
2.函数模板的原理
对于模板函数的使用,在编译器编译阶段,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码,对于字符类型也是如此。
3.函数模板的实例化
用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化。
(1) 隐式实例化:让编译器根据实参推演模板参数的实际类型.
template<class T>
T Add(const T& left, const T& right)
{ return left + right;}int main(){ int a1 = 10, a2 = 20; double d1 = 10.0, d2 = 20.0; Add(a1, a2); Add(d1, d2); /* 通过实参a1将T推演为int,通过实参d1将T推演为double类型,但模板参数列表中只有一个T,编译器无法确定此处到底该将T确定为int 或者 double类型而报错
如果我们想传两个不同类型的实参呢?此时有两种处理方式:
- 用户自己来强制转化
Add(a, (int)d);
- 使用显式实例化
显式实例化:在函数名后的<>中指定模板参数的实际类型.
int main(void)
{ int a = 10; double b = 20.0; Add<int>(a, b); // // 显式实例化 return 0;
}
3.类模板
(1).类模板的定义格式
template<class T1, class T2, ..., class Tn> class 类模板名
{
// 类内成员定义
};
#include<iostream>
using namespace std;
// 类模版
template<typename T>
class Stack
{
public:
Stack(size_t capacity = 4){ _array = new T[capacity]; _capacity = capacity; _size = 0; }void Push(const T& data);private: T* _array; size_t _capacity; size_t _size;
};
// 模版不建议声明和定义分离到两个文件.h 和.cpp会出现链接错误,具体原因后面会讲
template<class T>
void Stack<T>::Push(const T& data)
{// 扩容_array[_size] = data;++_size;
}
int main()
{Stack<int> st1; // intStack<double> st2; // doublereturn 0;
}
(2) 类模板的实例化
类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可。
// Stack是类名,Stack<int>才是类型
Stack<int> st1; // int
Stack<double> st2; // double
(完)