模板是泛型編程的基礎。所謂泛型編程就是編寫與類型無關的邏輯代碼,是一種複用的方式。模板分爲模板函數和模板類。
模板函數
假設現在要實現一個比較兩個數是否相等的重載函數。
bool IsEqual (int left, int right) { return left == right; } bool IsEqual (const string& left , const string& right) { return left == right; } void test1 () { string s1 ("s1"), s2("s2"); cout<<IsEqual (s1, s2)<<endl; cout<<IsEqual (1,1)<<endl; }
從代碼可以看出,如果我們要比較int和char類型需要分別編寫程序來解決這兩個問題,所以代碼的重複度就會很高,所以C++中就引入了模版來解決這個問題。
模板形參的定義既可以使用class,也可以使用typename,含義是相同的。上面的問題就可以簡化爲如下的代碼:
template<class T> bool IsEqual(const T& left, const T& right) { return left == right; } void test1 () { string s1 ("s1"), s2("s2" ); cout<<IsEqual (s1, s2)<<endl ; cout<<IsEqual (1,1)<<endl; }
對於T的類型,編譯器自己會通過推演得到T的類型,從而做出應有的處理。
在這,重點分享下模版的深入知識。
template<typename T> class SeqList { public: SeqList() :_array(NULL) , _size(0) , _capacity(0) {} ~SeqList() { if (_array) { delete[] _array; } } SeqList(const SeqList<T>& s) { _array = new T[s._size]; //memcpy(_array, s._array, sizeof(T)*s._size); for (size_t i = 0; i < s._size; i++)//根據size的大小來,原空間多大,同樣拷貝多大的空間 { _array[i] = s._array[i]; } _size = s._size; _capacity = s._capacity; } SeqList<T>& operator=(SeqList<T> s) { swap(_array, s._array); swap(_size, s._size); swap(_capacity, s._capacity); return *this; } void PushBack(const T& x) { _CheckCapacity(); _array[_size++] = x; } void Print() { for (int i = 0; i < _size; ++i) { cout << _array[i] << " "; } cout << endl; } void Reserve(size_t x) { _CheckCapacity(x); } T& operator[](size_t index) { assert(index < _size); return _array[index];//如果不用引用,那麼傳過來的是一塊臨時空間,只是將臨時空間的值給覆蓋了,如果使用引用那麼就是把對應的空間給出來,賦值的時候直接在原基礎上改動 } protected: void _CheckCapacity(size_t n) { if (n > _capacity) { _capacity = 2 * _capacity + 3 > n ? 2 * _capacity + 3 : n; /*_array = (T*)realloc(_array, sizeof(T)*_capacity);*/ T* tmp = new T[_capacity]; if (_array) /*memcpy(tmp, _array, sizeof(T)*_size);*/ for (size_t i = 0; i < _size; i++) { tmp[i] = _array[i]; } delete[] _array; _array = tmp; } } private: T* _array; size_t _size; size_t _capacity; }; //template<typename T> //在模版內聲明,在模版外定義與C++代碼寫順序表的區別 //void SeqList<T>::PushBack(const T& x)//作用域要寫類型名,而不是類名 //{ // //} void test1() { SeqList<int>s1; s1.PushBack(1); s1.PushBack(2); s1.PushBack(3); s1.PushBack(4); s1.Print(); SeqList<string> s2; s2.PushBack("xxx"); s2.PushBack("xxx"); s2.PushBack("xxx"); s2.PushBack("xxx"); s2.PushBack("xxx"); s2.Print(); SeqList<string> s3(s2); s3.Print(); SeqList<string> s4; s4.PushBack("yyy"); s4 = s3; s4.Print(); //string* p1 = (string*)malloc(sizeof(string));//指向的是字符串類,字符串類裏面不僅僅只包含了字符串指針,還有_size,_capacity等內容 //string* p2 = new string; //*p1 = "sss"; //*p2 = "sss"; } int main() { test1(); system("pause"); return 0; }