淺析C++中模板的那點事。本站提示廣大學習愛好者:(淺析C++中模板的那點事)文章只能為提供參考,不一定能成為您想要的結果。以下是淺析C++中模板的那點事正文
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函數外部所要完成的操作也是極端的類似。以下:
int fun(int x,int y)
{
int tmp = x *x + y * y + x * y;
return tmp;
}
float fun(float x,float y)
{
float tmp = x *x + y * y + x * y;
return tmp;
}
double fun(double x,double y)
{
double tmp = x *x + y * y + x * y;
return tmp;
}
可以看出,下面的三個函數體除類型紛歧樣以外,其他的完整一樣,那末假如可以或許只寫一個函數就可以完成下面的三個函數的功效該多好呢?假如從這三個函數提煉出一個通用函數,而它又實用於這三種分歧類型的數據,如許會使代碼的重用率年夜年夜進步。現實上C++中的模板正好就是來處理這個成績的。模板可以完成類型的參數化(把類型界說為參數),從而完成了真實的代碼可重用性。C++中的模板可分為函數模板和類模板,而把函數模板的詳細化稱為模板函數,把類模板的詳細化成為模板類。上面讓我們分離看看甚麼是函數模板和類模板吧~~~
2.模板函數
現實上我們應用函數模板,只須要一個函數便可能完成下面的三個函數了,千言萬語不如看代碼:
#include <iostream>
using namespace std;
template <typename T>
T fun(T x,T y)
{
T tmp = x *x + y * y + x * y;
return tmp;
}
int main()
{
int x1 = 1,y1 = 4;
float x2 = 1.1 , y2 = 2.2;
double x3 = 2.0 , y3 = 3.1;
cout<<fun(x1,y1)<<endl;
cout<<fun(x2,y2)<<endl;
cout<<fun(x3,y3)<<endl;
return 0;
}
運轉成果:
如斯應用模板,我們很易如反掌的到達了我們的目標,而這也年夜年夜的進步了代碼的可重用性,這也讓我們想起了STL中的那些算法了吧,這些算法應用多種的數據類型。現實上STL即便模板的主要運用了。
如今我們想,假如下面的代碼如許挪用fun(x1,y2)會怎樣樣呢?點擊編譯會湧現如許的毛病:
可以看到編譯編譯湧現成績的是fun(x1,y2),說的意思就是沒有對應的函數,要末x1和y2都是int型,要末x1和y2都是float型。那末我為何要說一下如許一種情形呢?重要是為了引出模板也能夠同時應用兩個:
#include <iostream>
using namespace std;
template <typename T1 , typename T2>
T2 fun(T1 x,T2 y)
{
T2 tmp = x *x + y * y + x * y;
return tmp;
}
int main()
{
int x1 = 1,y1 = 4;
float x2 = 1.1 , y2 = 2.2;
double x3 = 2.0 , y3 = 3.1;
cout<<fun(x1,y1)<<endl;
cout<<fun(x2,y2)<<endl;
cout<<fun(x3,y3)<<endl;
cout<<fun(x1,y2)<<endl;
return 0;
}
運轉成果:
當應用兩個模板時,為何fun(x1,y1)也能准確運轉呢?由於當停止這個挪用時,T1 = int ,T2 = int。所以這類挪用也是沒有成績的。
提到函數想到重載是很天然的吧,那末模板函數能不克不及重載呢?明顯是能的了,照樣看代碼:
#include <iostream>
using namespace std;
template <typename T1 , typename T2>
T2 fun(T1 x,T2 y)
{
cout<<"挪用了兩個個參數的 fun 函數 ^^ "<<endl;
T2 tmp = x *x + y * y + x * y;
return tmp;
}
template <typename T>
T fun(T x , T y , T z)
{
cout<<"挪用了三個參數的 fun 函數 ^^ "<<endl;
T tmp = x * x + y * y + z * z + x * y * z;
return tmp;
}
int main()
{
int x1 = 1 , y1 = 4 , z1 = 5;
float x2 = 1.1 , y2 = 2.2;
double x3 = 2.0 , y3 = 3.1;
cout<<fun(x1,y1)<<endl;
cout<<fun(x2,y2)<<endl;
cout<<fun(x3,y3)<<endl;
cout<<fun(x1,y2)<<endl;
cout<<fun(x1,y1,z1)<<endl;
return 0;
}
運轉成果:
從成果曾經能看出來模版函數的重載是沒有任何成績的了。那末模板函數和非模板函數之間能否可以或許重載呢??
#include <iostream>
using namespace std;
template <typename T>
T fun(T x,T y)
{
cout<<"挪用了模板函數 ^^ "<<endl;
T tmp = x * x + y * y + x * y;
return tmp;
}
int fun(int x,int y)
{
cout<<"挪用了非模板函數 ^^ "<<endl;
int tmp = x * x + y * y + x * y;
return tmp;
}
int main()
{
int x1 = 1 , y1 = 4;
float x2 = 1.1 , y2 = 2.2;
cout<<fun(x1,y1)<<endl;
cout<<fun(x2,y2)<<endl;
return 0;
}
運轉成果:
看以看出模版函數和非模板函數也是能夠重載的,那末重載函數的挪用次序是怎樣樣的呢?現實上是先查找非模板函數,要有嚴厲婚配的非模板函數,就挪用非模板函數,找不到合適的非模板函數在和模板函數停止婚配。
到這裡,關於模板就說這些吧~~~~
3.模板類
如果懂得了模版函數,模板類就相當的簡略了,只不外模版函數是對函數中的類型應用模板,而模板類是對類中的類型應用模板,這我就不多說了,上面的代碼是我之前應用模板寫的單鏈表,這個是模板的典范運用:(測試過)
#include <stdio.h>
#include <iostream.h>
template <class T>
struct SLNode
{
T data;
SLNode<T> *next;
SLNode(SLNode<T> *nextNode=NULL)
{
next = nextNode;
}
SLNode(const T &item,SLNode<T> *nextNode=NULL)
{
data = item;
next = nextNode;
}
};
template <class T>
class SLList
{
private:
SLNode<T> *head;
SLNode<T> *tail;
SLNode<T> *currptr;
int size;
public:
SLList();
SLList(const T &item);
~SLList();
bool IsEmpty()const;
int Length()const;
bool Find(int k,T &item)const;
int Search(const T &item)const;
void InsertFromHead(const T &item);
void InsertFromTail(const T &item);
bool DeleteFromHead(T &item);
bool DeleteFromTail(T &item);
void Insert(int k,const T &item);
void Delete(int k,T &item);
void ShowListMember();
};
//結構函數
template <class T>
SLList<T>::SLList()
{
head = tail = currptr = new SLNode<T>();
size = 0;
}
//結構函數
template <class T>
SLList<T>::SLList(const T &item)
{
tail = currptr = new SLNode<T>(item);
head = new SLNode<T>(currptr);
size = 1;
}
//析構函數
template <class T>
SLList<T>::~SLList()
{
SLNode<T> *temp;
while(!IsEmpty())
{
temp = head->next;
head->next = temp->next;
delete temp;
}
}
//斷定鏈表能否為空
template <class T>
bool SLList<T>::IsEmpty()const
{
return head->next == NULL;
}
//前往鏈表的長度
template <class T>
int SLList<T>::Length()const
{
return size;
}
//查找第k個節點的阈值
template <class T>
bool SLList<T>::Find(int k,T &item)const
{
if(k < 1)
{
cout<<"illegal position !"<<endl;
}
SLNode<T> *temp = head;
int count = 0;
while(temp != NULL && count < k)
{
temp = temp->next;
count++;
}
if(temp == NULL)
{
cout<<"The list does not contain the K node !"<<endl;
return false;
}
item = temp->data;
return true;
}
//查找data阈值為item是表的第幾個元素
template <class T>
int SLList<T>::Search(const T &item)const
{
SLNode<T> *temp = head->next;
int count = 1;
while(temp != NULL && temp->data != item)
{
temp = temp->next;
count++;
}
if(temp == NULL)
{
cout<<"The node does not exist !"<<endl;
return -1;
}
else
{
return count;
}
}
//從表頭拔出
template <class T>
void SLList<T>::InsertFromHead(const T &item)
{
if(IsEmpty())
{
head->next = new SLNode<T>(item,head->next);
tail = head->next;
}
else
{
head->next = new SLNode<T>(item,head->next);
}
size++;
}
//從表尾拔出
template <class T>
void SLList<T>::InsertFromTail(const T &item)
{
tail->next = new SLNode<T>(item,NULL);
tail = tail->next;
size++;
}
//從表頭刪除
template <class T>
bool SLList<T>::DeleteFromHead(T &item)
{
if(IsEmpty())
{
cout<<"This is a empty list !"<<endl;
return false;
}
SLNode<T> *temp = head->next;
head->next = temp->next;
size--;
item = temp->data;
if(temp == tail)
{
tail = head;
}
delete temp;
return true;
}
//從表尾刪除
template <class T>
bool SLList<T>::DeleteFromTail(T &item)
{
if(IsEmpty())
{
cout<<"This is a empty list !"<<endl;
return false;
}
SLNode<T> *temp = head;
while(temp->next != tail)
{
temp = temp->next;
}
item = tail->data;
tail = temp;
tail->next=NULL;
temp = temp->next;
delete temp;
size--;
return true;
}
//在第k個節點後拔出item值
template <class T>
void SLList<T>::Insert(int k,const T &item)
{
if(k < 0 || k > size)
{
cout<<"Insert position Illegal !"<<endl;
return;
}
if(k == 0)
{
InsertFromHead(item);
return;
}
if(k == size)
{
InsertFromTail(item);
return;
}
SLNode<T> *temp = head->next;
int count = 1;
while(count < k)
{
count++;
temp = temp->next;
}
SLNode<T> *p = temp->next;
temp->next = new SLNode<T>(item,p);
size++;
}
//刪除第k個節點的值,保留在item中
template <class T>
void SLList<T>::Delete(int k,T &item)
{
if(k <= 0 || k > size)
{
cout<<"Ileegal delete position !"<<endl;
return;
}
if(k == 1)
{
DeleteFromHead(item);
return;
}
if(k == size)
{
DeleteFromTail(item);
return;
}
SLNode<T> *temp = head->next;
int count = 1;
while(count < k-1)
{
count++;
temp = temp->next;
}
SLNode<T> *p = temp->next;
temp->next = p->next;
p->next = NULL;
item = p->data;
delete p;
size--;
}
template <class T>
void SLList<T>::ShowListMember()
{
cout<<"List Member : ";
SLNode<T> *temp = head->next;
while(temp != NULL)
{
cout<<temp->data<<" ";
temp = temp->next;
}
cout<<endl;
}
/*
1.引入了InsertFronHead,InsertFromTail,DeleteFromHead和DeleteFromTail用來完成Insert和Delete函數,是一個比擬好的辦法。
2.SLNode(T &item,SLNode<T> *nextNode)這個結構函數設計的異常奇妙,便於其他成員函數的完成。
3.拔出,刪除分為:表頭,表尾,中央拔出(刪除)三種情形
*/
int main()
{
int item;
SLList<int> list(12);
list.Insert(0,11);
cout<<"list number:"<<list.Length()<<endl;
list.ShowListMember();
list.Insert(2,14);
cout<<"list number:"<<list.Length()<<endl;
list.ShowListMember();
list.Insert(2,13);
cout<<"list number:"<<list.Length()<<endl;
list.ShowListMember();
list.Delete(2,item);
cout<<"item = "<<item<<endl;
cout<<"list number:"<<list.Length()<<endl;
list.ShowListMember();
list.Delete(1,item);
cout<<"item = "<<item<<endl;
cout<<"list number:"<<list.Length()<<endl;
list.ShowListMember();
list.Delete(2,item);
cout<<"item = "<<item<<endl;
cout<<"list number:"<<list.Length()<<endl;
list.ShowListMember();
return 0;
}
應用模板的利益是,SLList中的數據可所以隨意率性的數據類型,這也就是泛型編程的概念了吧~~~~