模板是泛型編程的基礎,即與類型無關的邏輯代碼。
利用模板機制可以顯著減少冗餘信息,能大幅度地節約程序代碼,進一步提高面向對象程序的可重用性和可維護性。
模板是實現代碼重用機制的一種工具,它可以實現類型參數化;
模板分爲函數模板和類模板。
爲了使用函數名相同,參數不同,返回值可同可不同的函數時,我們起初用了重載的方式。
#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; }