模板是泛型编程的基础,即与类型无关的逻辑代码。
利用模板机制可以显著减少冗余信息,能大幅度地节约程序代码,进一步提高面向对象程序的可重用性和可维护性。
模板是实现代码重用机制的一种工具,它可以实现类型参数化;
模板分为函数模板和类模板。
为了使用函数名相同,参数不同,返回值可同可不同的函数时,我们起初用了重载的方式。
#include<iostream>
using namespace std;
int add(int a,int b)
{
return a+b;
}
double add(double a,double b)
{
return a+b;
}
int main()
{
cout<<"ret1="<<add(1,2)<<endl;
cout<<"ret2="<<add(2.3,3.0)<<endl;
getchar();
return 0;
}
但是运用重载的方式写起来比较不方便,尤其是重载的函数较多时,为了解决这类问题,我们用函数模板来实现这种功能。
#include<iostream>
using namespace std;
template <class T>
T add(const T& a,const T& b)
{
cout<<"type:"<<typeid(a).name()<<endl; //显示类型
return a+b;
}
int main()
{
cout<<"ret1="<<add(1,2)<<endl;//还可以显示实例化,显示指定T为int,即add<int>(1,2)
cout<<"ret2="<<add(2.3,3.0)<<endl; //add<double>(2.3,3.0)
getchar();
return 0;
}
以上函数中函数参数类型都是相同的,当我们遇到形如:add(1,2.3);一个参数为int,一个参数为double型,此时我们可以这样定义:
template <class T1,class T2>
T add(const T1& a,const T2& b)
{
return a+b;
}
当然,肯定有人会想,模板函数可以构成重载吗? 答案是肯定的。
#include<iostream>
using namespace std;
int add(int a,int b)
{
return a+b;
}
double add(double a,double b)
{
return a+b;
}
template <class T>
T add(const T& a,const T& b)
{
cout<<"type:"<<typeid(a).name()<<endl;
return a+b;
}
int main()
{
cout<<"ret1="<<add(1,2)<<endl;
cout<<"ret2="<<add(2.3,3.0)<<endl;
getchar();
return 0;
}
当模板构成重载,调用add的函数时,它会先调用非模板类的函数,性能比较高;而模板函数内部还得调用,有推演过程判断它是什么类型,效率上会有所降低。
2.模板类
对于普通函数来说,我们拿typedef重定义一个类型,当需要改的时候,需要将int改掉就可以了;
typedef int DataType;
class SEQLIST
{
private:
DataType *data;
};
而我们为了适应更多的类型,于是引入了模板类,我们这样定义,体现了其高度复用的优势:
template<class T>
class SeqList
{
private:
T* data;
};
写一个模板类实现SeqList的动态顺序表吧:
#include<iostream>
using namespace std;
template <class T>
class SeqList
{
public:
SeqList()
:_data(NULL)
,_size(0)
,_capacity(0)
{}
SeqList(const SeqList<T>& s);
SeqList<T>& operator=(const SeqList<T>& s);
~SeqList()
{
if(_data != NULL)
{
delete[] _data;
}
}
void CheckCapacity();
void PushBack(const T& d);
void PopBack();
void PushFront(const T& d);
void PopFront();
void Print();
private:
T *_data;
int _size;
int _capacity;
};
template <class T>
SeqList<T>::SeqList(const SeqList<T>& s)
{
_data = new T[s._size*sizeof(T)];
int i = 0;
for(i = 0;i < s._size; i++)
{
_data[i] = s._data[i];
}
_size = s._size;
_capacity = s._capacity;
}
template <class T>
SeqList<T>& SeqList<T>::operator=(const SeqList<T>& s)
{
int i = 0;
if(this == &s)
{
return *this;
}
_size = s._size;
_capacity = s._capacity;
delete _data;
_data = new T[_capacity];
for(i = 0; i < _size; i++)
{
_data[i] = s._data[i];
}
return *this;
}
template <class T>
void SeqList<T>::CheckCapacity()
{
if(_size == _capacity)
{
T* tmp = new T[_capacity*2+3];
//memcpy(tmp,_data,_size*sizeof(T));
int i = 0;
for(i = 0; i < _size; i++)
{
tmp[i] = _data[i];
}
delete[] _data;
_data = tmp;
_capacity = _capacity*2+3;
}
}
template <class T>
void SeqList<T>::PushBack(const T& d)
{
CheckCapacity();
_data[_size] = d;
_size++;
}
template <class T>
void SeqList<T>::PopBack()
{
CheckCapacity();
_size--;
}
template <class T>
void SeqList<T>::PushFront(const T& d)
{
int i ;
CheckCapacity();
for(i = _size; i > 0; i--)
{
_data[i] = _data[i-1];
}
_data[0] = d;
_size++;
}
template <class T>
void SeqList<T>::PopFront()
{
int i;
CheckCapacity();
for(i = 0; i < _size; i++)
{
_data[i] = _data[i+1];
}
_size--;
}
template <class T>
void SeqList<T>::Print()
{
int i = 0;
for(i = 0; i < _size; i++)
{
cout<<_data[i]<<" ";
}
cout<<endl;
}
int main()
{
SeqList<int> seq;
SeqList<int> seq1;
cout<<"seq:"<<endl;
cout<<"尾插1234"<<endl;
seq.PushBack(1);
seq.PushBack(2);
seq.PushBack(3);
seq.PushBack(4);
seq.Print();
cout<<"尾删"<<endl;
seq.PopBack();
seq.Print();
cout<<"头删"<<endl;
seq.PopFront();
seq.Print();
cout<<"seq2:"<<endl;
SeqList<int> seq2(seq);
seq2.Print();
cout<<"头插567"<<endl;
seq.PushFront(5);
seq.PushFront(6);
seq.PushFront(7);
seq.Print();
seq1 = seq;
cout<<"seq1:"<<endl;
seq1.Print();
getchar();
return 0;
}