1.什么是模板
假設現在我們完成這樣的函數,給定兩個數x和y求式子x^2 + y^2 + x * y的值 .考慮到x和y可能是 int , float 或者double類型,那么我們就要完成三個函數:
int fun(int x,int y);
float fun(float x,float y);
double fun(double x,double y);
並且每個fun函數內部所要完成的操作也是極其的相似。如下:
View Code
1 int fun(int x,int y) 2 { 3 int tmp = x *x + y * y + x * y; 4 return tmp; 5 } 6 float fun(float x,float y) 7 { 8 float tmp = x *x + y * y + x * y; 9 return tmp; 10 } 11 double fun(double x,double y) 12 { 13 double tmp = x *x + y * y + x * y; 14 return tmp; 15 }
可以看出,上面的三個函數體除了類型不一樣之外,其他的完全一樣,那么如果能夠只寫一個函數就能完成上面的三個函數的功能該多好呢?如果從這三個函數提煉出一個通用函數,而它又適用於這三種不同類型的數據,這樣會使代碼的重用率大大提高。實際上C++中的模板正好就是來解決這個問題的。模板可以實現類型的參數化(把類型定義為參數),從而實現了真正的代碼可重用性。C++中的模板可分為函數模板和類模板,而把函數模板的具體化稱為模板函數,把類模板的具體化成為模板類。下面讓我們分別看看什么是函數模板和類模板吧~~~
2.模板函數
實際上我們利用函數模板,只需要一個函數就可能完成上面的三個函數了,千言萬語不如看代碼:
View Code
1 #include <iostream> 2 3 using namespace std; 4 5 template <typename T> 6 T fun(T x,T y) 7 { 8 T tmp = x *x + y * y + x * y; 9 return tmp; 10 } 11 int main() 12 { 13 int x1 = 1,y1 = 4; 14 float x2 = 1.1 , y2 = 2.2; 15 double x3 = 2.0 , y3 = 3.1; 16 cout<<fun(x1,y1)<<endl; 17 cout<<fun(x2,y2)<<endl; 18 cout<<fun(x3,y3)<<endl; 19 return 0; 20 }
運行結果:

如此利用模板,我們很輕而易舉的達到了我們的目的,而這也大大的提高了代碼的可重用性,這也讓我們想起了STL中的那些算法了吧,這些算法使用多種的數據類型。實際上STL即使模板的重要應用了。
現在我們想,如果上面的代碼這樣調用fun(x1,y2)會怎么樣呢?點擊編譯會出現這樣的錯誤:

可以看到編譯編譯出現問題的是fun(x1,y2),說的意思就是沒有對應的函數,要么x1和y2都是int型,要么x1和y2都是float型。那么我為什么要說一下這樣一種情況呢?主要是為了引出模板也可以同時使用兩個:
View Code
1 #include <iostream> 2 3 using namespace std; 4 5 6 template <typename T1 , typename T2> 7 T2 fun(T1 x,T2 y) 8 { 9 T2 tmp = x *x + y * y + x * y; 10 return tmp; 11 } 12 int main() 13 { 14 int x1 = 1,y1 = 4; 15 float x2 = 1.1 , y2 = 2.2; 16 double x3 = 2.0 , y3 = 3.1; 17 cout<<fun(x1,y1)<<endl; 18 cout<<fun(x2,y2)<<endl; 19 cout<<fun(x3,y3)<<endl; 20 cout<<fun(x1,y2)<<endl; 21 return 0; 22 }
運行結果:

當使用兩個模板時,為什么fun(x1,y1)也能正確運行呢?因為當進行這個調用時,T1 = int ,T2 = int。所以這種調用也是沒有問題的。
提到函數想到重載是很自然的吧,那么模板函數能不能重載呢?顯然是能的了,還是看代碼:
View Code
1 #include <iostream> 2 3 using namespace std; 4 5 6 template <typename T1 , typename T2> 7 T2 fun(T1 x,T2 y) 8 { 9 cout<<"調用了兩個個參數的 fun 函數 ^^ "<<endl; 10 T2 tmp = x *x + y * y + x * y; 11 return tmp; 12 } 13 template <typename T> 14 T fun(T x , T y , T z) 15 { 16 cout<<"調用了三個參數的 fun 函數 ^^ "<<endl; 17 T tmp = x * x + y * y + z * z + x * y * z; 18 return tmp; 19 } 20 int main() 21 { 22 int x1 = 1 , y1 = 4 , z1 = 5; 23 float x2 = 1.1 , y2 = 2.2; 24 double x3 = 2.0 , y3 = 3.1; 25 cout<<fun(x1,y1)<<endl; 26 cout<<fun(x2,y2)<<endl; 27 cout<<fun(x3,y3)<<endl; 28 cout<<fun(x1,y2)<<endl; 29 cout<<fun(x1,y1,z1)<<endl; 30 return 0; 31 }
運行結果:

從結果已經能看出來模版函數的重載是沒有任何問題的了。那么模板函數和非模板函數之間是否能夠重載呢??
View Code
1 #include <iostream> 2 3 using namespace std; 4 5 template <typename T> 6 T fun(T x,T y) 7 { 8 cout<<"調用了模板函數 ^^ "<<endl; 9 T tmp = x * x + y * y + x * y; 10 return tmp; 11 } 12 int fun(int x,int y) 13 { 14 cout<<"調用了非模板函數 ^^ "<<endl; 15 int tmp = x * x + y * y + x * y; 16 return tmp; 17 } 18 19 int main() 20 { 21 int x1 = 1 , y1 = 4; 22 float x2 = 1.1 , y2 = 2.2; 23 cout<<fun(x1,y1)<<endl; 24 cout<<fun(x2,y2)<<endl; 25 return 0; 26 }
運行結果:

看以看出模版函數和非模板函數也是可能重載的,那么重載函數的調用順序是怎么樣的呢?實際上是先查找非模板函數,要有嚴格匹配的非模板函數,就調用非模板函數,找不到適合的非模板函數在和模板函數進行匹配。
到這里,關於模板就說這些吧~~~~
3.模板類
要是理解了模版函數,模板類就相當的簡單了,只不過模版函數是對函數中的類型使用模板,而模板類是對類中的類型使用模板,這我就不多說了,下面的代碼是我以前利用模板寫的單鏈表,這個是模板的典型應用:(測試過)
View Code
1 #include <stdio.h> 2 #include <iostream.h> 3 4 template <class T> 5 struct SLNode 6 { 7 T data; 8 SLNode<T> *next; 9 SLNode(SLNode<T> *nextNode=NULL) 10 { 11 next = nextNode; 12 } 13 SLNode(const T &item,SLNode<T> *nextNode=NULL) 14 { 15 data = item; 16 next = nextNode; 17 } 18 }; 19 20 template <class T> 21 class SLList 22 { 23 private: 24 SLNode<T> *head; 25 SLNode<T> *tail; 26 SLNode<T> *currptr; 27 int size; 28 public: 29 SLList(); 30 SLList(const T &item); 31 ~SLList(); 32 bool IsEmpty()const; 33 int Length()const; 34 bool Find(int k,T &item)const; 35 int Search(const T &item)const; 36 void InsertFromHead(const T &item); 37 void InsertFromTail(const T &item); 38 bool DeleteFromHead(T &item); 39 bool DeleteFromTail(T &item); 40 void Insert(int k,const T &item); 41 void Delete(int k,T &item); 42 void ShowListMember(); 43 }; 44 //構造函數 45 template <class T> 46 SLList<T>::SLList() 47 { 48 head = tail = currptr = new SLNode<T>(); 49 size = 0; 50 } 51 //構造函數 52 template <class T> 53 SLList<T>::SLList(const T &item) 54 { 55 tail = currptr = new SLNode<T>(item); 56 head = new SLNode<T>(currptr); 57 size = 1; 58 } 59 //析構函數 60 template <class T> 61 SLList<T>::~SLList() 62 { 63 SLNode<T> *temp; 64 while(!IsEmpty()) 65 { 66 temp = head->next; 67 head->next = temp->next; 68 delete temp; 69 70 } 71 } 72 //判斷鏈表是否為空 73 template <class T> 74 bool SLList<T>::IsEmpty()const 75 { 76 return head->next == NULL; 77 } 78 //返回鏈表的長度 79 template <class T> 80 int SLList<T>::Length()const 81 { 82 return size; 83 } 84 //查找第k個節點的閾值 85 template <class T> 86 bool SLList<T>::Find(int k,T &item)const 87 { 88 if(k < 1) 89 { 90 cout<<"illegal position !"<<endl; 91 } 92 SLNode<T> *temp = head; 93 int count = 0; 94 while(temp != NULL && count < k) 95 { 96 temp = temp->next; 97 count++; 98 } 99 if(temp == NULL) 100 { 101 cout<<"The list does not contain the K node !"<<endl; 102 return false; 103 } 104 item = temp->data; 105 return true; 106 } 107 //查找data閾值為item是表的第幾個元素 108 template <class T> 109 int SLList<T>::Search(const T &item)const 110 { 111 SLNode<T> *temp = head->next; 112 int count = 1; 113 while(temp != NULL && temp->data != item) 114 { 115 temp = temp->next; 116 count++; 117 } 118 if(temp == NULL) 119 { 120 cout<<"The node does not exist !"<<endl; 121 return -1; 122 } 123 else 124 { 125 return count; 126 } 127 } 128 //從表頭插入 129 template <class T> 130 void SLList<T>::InsertFromHead(const T &item) 131 { 132 if(IsEmpty()) 133 { 134 head->next = new SLNode<T>(item,head->next); 135 tail = head->next; 136 } 137 else 138 { 139 head->next = new SLNode<T>(item,head->next); 140 } 141 size++; 142 } 143 //從表尾插入 144 template <class T> 145 void SLList<T>::InsertFromTail(const T &item) 146 { 147 tail->next = new SLNode<T>(item,NULL); 148 tail = tail->next; 149 size++; 150 } 151 //從表頭刪除 152 template <class T> 153 bool SLList<T>::DeleteFromHead(T &item) 154 { 155 if(IsEmpty()) 156 { 157 cout<<"This is a empty list !"<<endl; 158 return false; 159 } 160 SLNode<T> *temp = head->next; 161 head->next = temp->next; 162 size--; 163 item = temp->data; 164 if(temp == tail) 165 { 166 tail = head; 167 } 168 delete temp; 169 return true; 170 } 171 //從表尾刪除 172 template <class T> 173 bool SLList<T>::DeleteFromTail(T &item) 174 { 175 if(IsEmpty()) 176 { 177 cout<<"This is a empty list !"<<endl; 178 return false; 179 } 180 SLNode<T> *temp = head; 181 while(temp->next != tail) 182 { 183 temp = temp->next; 184 } 185 item = tail->data; 186 tail = temp; 187 tail->next=NULL; 188 temp = temp->next; 189 delete temp; 190 size--; 191 return true; 192 } 193 //在第k個節點后插入item值 194 template <class T> 195 void SLList<T>::Insert(int k,const T &item) 196 { 197 if(k < 0 || k > size) 198 { 199 cout<<"Insert position Illegal !"<<endl; 200 return; 201 } 202 if(k == 0) 203 { 204 InsertFromHead(item); 205 return; 206 } 207 if(k == size) 208 { 209 InsertFromTail(item); 210 return; 211 } 212 SLNode<T> *temp = head->next; 213 int count = 1; 214 while(count < k) 215 { 216 count++; 217 temp = temp->next; 218 } 219 SLNode<T> *p = temp->next; 220 temp->next = new SLNode<T>(item,p); 221 size++; 222 } 223 //刪除第k個節點的值,保存在item中 224 template <class T> 225 void SLList<T>::Delete(int k,T &item) 226 { 227 if(k <= 0 || k > size) 228 { 229 cout<<"Ileegal delete position !"<<endl; 230 return; 231 } 232 if(k == 1) 233 { 234 DeleteFromHead(item); 235 return; 236 } 237 if(k == size) 238 { 239 DeleteFromTail(item); 240 return; 241 } 242 SLNode<T> *temp = head->next; 243 int count = 1; 244 while(count < k-1) 245 { 246 count++; 247 temp = temp->next; 248 } 249 SLNode<T> *p = temp->next; 250 temp->next = p->next; 251 p->next = NULL; 252 item = p->data; 253 delete p; 254 size--; 255 } 256 template <class T> 257 void SLList<T>::ShowListMember() 258 { 259 cout<<"List Member : "; 260 SLNode<T> *temp = head->next; 261 while(temp != NULL) 262 { 263 cout<<temp->data<<" "; 264 temp = temp->next; 265 } 266 cout<<endl; 267 } 268 269 /* 270 1.引入了InsertFronHead,InsertFromTail,DeleteFromHead和DeleteFromTail用來實現 271 Insert和Delete函數,是一個比較好的方法。 272 2.SLNode(T &item,SLNode<T> *nextNode)這個構造函數設計的非常巧妙,便於其他成員 273 函數的實現。 274 3.插入,刪除分為:表頭,表尾,中間插入(刪除)三種情況 275 */ 276 277 278 279 int main() 280 { 281 int item; 282 SLList<int> list(12); 283 284 list.Insert(0,11); 285 cout<<"list number:"<<list.Length()<<endl; 286 list.ShowListMember(); 287 288 list.Insert(2,14); 289 cout<<"list number:"<<list.Length()<<endl; 290 list.ShowListMember(); 291 292 list.Insert(2,13); 293 cout<<"list number:"<<list.Length()<<endl; 294 list.ShowListMember(); 295 296 list.Delete(2,item); 297 cout<<"item = "<<item<<endl; 298 cout<<"list number:"<<list.Length()<<endl; 299 list.ShowListMember(); 300 301 list.Delete(1,item); 302 cout<<"item = "<<item<<endl; 303 cout<<"list number:"<<list.Length()<<endl; 304 list.ShowListMember(); 305 306 list.Delete(2,item); 307 cout<<"item = "<<item<<endl; 308 cout<<"list number:"<<list.Length()<<endl; 309 list.ShowListMember(); 310 return 0; 311 }
利用模板的好處是,SLList中的數據可以是任意的數據類型,這也就是泛型編程的概念了吧~~~~
學習中的一點總結,歡迎拍轉哦^^
