C++中的模板

来源:互联网 发布:探索者软件华北区 编辑:程序博客网 时间:2024/06/05 12:37
1.模板
模板是泛型编程的基础。即编写与类型无关的逻辑代码,也是一种复用的方式。
C++中的模板分为:模板函数、模板类
(1)模板函数
函数模板格式:template<class/typename 形参名1,class/typename 形参名2,class/typename 形参名n>
例子:实现一个比较两个数是否相符


template <typename T>
bool IsEqual(const T& left, const T& right)
{
return left==right;
}
明显的,模板实现了代码的复用,那么模板是如何实现不同类型的参数调用时刚还对号入座呢?
原来,编译器调用模板时,编译器会根据传递的参数自动推演出模板形参的类型,并且自动生成
对应的代码。如下图所示:

需要注意的是:
(1)按照以上例子,如果调用IsEqual(1,1.2)时,两个参数不匹配的情况,我们可以做一个变换
<double>IsEqual(1,1.2),这个过程叫做显示实例化
(2)如果模板自己就定义了两个不相同类型的参数,如下
template <typename T1, typename T2>
bool IsEqual (const T1& left , const T2& right)
{
 return left == right;
}
如果调用IsEqual(1,1),编译器先检查,看是否有两个参数都是int型的函数IsEqual()
如果有优先调用它,否则再调用模板函数,这就是模板实例化后的函数与原函数构成重载

(2)模板类
模板类格式:
template<class/typename 形参名1,class/typename 形参名2,...class/typename 形参名n>
class 类名
{...};
例子:用模板类实现动态顺序表
#include <iostream>#include <assert.h>#include <string>using namespace std;template <typename T>class SeqList{private:T* _a;size_t _size;size_t _capacity;public:SeqList()//构造函数:_a(NULL),_size(0),_capacity(0){//cout<<"SeqList()//构造函数"<<endl;}~SeqList()//析构函数{if(_a){delete[] _a;}}SeqList(const SeqList<T>& s)//拷贝构造{_a=new T[s._size];for(size_t i=0;i<s._size;i++){_a[i]=s._a[i];}_size=s._size;_capacity=_size;}SeqList<T>& operator=(const SeqList<T> s)//赋值运算符的重载{swap(s._a, _a);swap(s._size,_size);swap(s._capacity,_capacity);return *this;}    void CheckCapacity()//判断并且增容{if(_size==_capacity){size_t newSize=_capacity?_capacity*2:3;//刚进来增到3,下次每次增2倍容T* tmp=new T[newSize];for(size_t i=0; i<_size;i++){tmp[i]=_a[i];//执行赋值运算符的重载}delete[] _a;_a=tmp;_capacity=newSize;assert(_a);}}void PushBack(const T& x)//后插{CheckCapacity();_a[_size++]=x;} void PopBack()//后删{_size--;}void Insert(size_t pos, const T& x)//在某个位置前插入一个元素{CheckCapacity();assert(pos>=0);for(size_t i=_size;i>pos;i--){_a[i]=_a[i-1];}_a[pos]=x;_size++;}void Erase(size_t pos)//删除{assert(pos>=0);for(size_t i=pos;i<_size-1;i++){_a[i]=_a[i+1];}_size--;}T& operator[](size_t pos)//[]重载{assert((pos>=0)&&(pos<_size));return _a[pos];}void Print()//打印元素{//int i=0;for(size_t i=0;i<_size;i++){cout<<_a[i]<<" ";}cout<<endl;}};
需要注意的是:
(1)这时候,模板类的类型不是SeqList,而是SeqList<T>.
(2)需要开辟空间的时候用new,而不能用realloc,因为用new回调用函数初始化空间,导致每次释放没问题
而realloc第一次进来相当于malloc,空间内容没有初始化,导致释放随机值有问题。
(3)和模板函数类似,在调用模板类的时候,编译器也会根据类型SeqList<T>来模板推演处理,自己
换取相对应类型的模板,如下图所示: