我們在使用重載函數時,只是使用了函數名,而函數體還是得分別定義,在C++中函數模板爲我們很好的解決了這個問題.
1.函數模板的聲明
函數模板可以用來創建一個通用的函數,以支持多種不同的形參,避免重載函數的函數體重複設計。它的最大特點是把函數使用的數據類型作爲參數。
函數模板的聲明形式爲:
template<typename 數據類型參數標識符>
<返回類型><函數名>(參數表)
{
函數體
}
其中,template是定義模板函數的關鍵字;template後面的尖括號不能省略;typename(或class)是聲明數據類型參數標識符的關鍵字,用來說明它後面的標識符是數據類型標識符。這樣,在以後定義的這個函數中,凡希望根據實參數據類型來確定數據類型的變量,都可以用數據類型參數標識符來說明,從而使這個變量可以適應不同的數據類型。例如:
template<typename T>
T func(T x, int y)
{
T x;
//……
}
函數模板只是聲明瞭一個函數的描述即模板,不是一個可以直接執行的函數,只有根據實際情況用實參的數據類型代替類型參數標識符之後,才能產生真正的函數。
關鍵字typename也可以使用關鍵字class,這時數據類型參數標識符就可以使用所有的C++數據類型。
2.模板函數的生成
函數模板的數據類型參數標識符實際上是一個類型形參,在使用函數模板時,要將這個形參實例化爲確定的數據類型。將類型形參實例化的參數稱爲模板實參,用模板實參實例化的函數稱爲模板函數。模板函數的生成就是將函數模板的類型形參實例化的過程。
使用中應注意的幾個問題:
⑴ 函數模板允許使用多個類型參數,但在template定義部分的每個形參前必須有關鍵字typename或class,即:
template<class 數據類型參數標識符1,…,class 數據類型參數標識符n>
<返回類型><函數名>(參數表)
{
函數體
}
⑵ 在template語句與函數模板定義語句之間不允許有別的語句。如下面的聲明是錯誤的:
template<class T>
int I;
T min(T x,T y)
{
函數體
}
⑶ 模板函數類似於重載函數,但兩者有很大區別:函數重載時,每個函數體內可以執行不同的動作,但同一個函數模板實例化後的模板函數都必須執行相同的動作
3. 函數模板的異常處理
函數模板中的模板形參可實例化爲各種類型,但當實例化模板形參的各模板實參之間不完全一致時,就可能發生錯誤,C++中,函數模板與同名的非模板函數重載時,應遵循下列調用原則:
• 尋找一個參數完全匹配的函數,若找到就調用它。若參數完全匹配的函數多於一個,則這個調用是一個錯誤的調用。
• 尋找一個函數模板,若找到就將其實例化生成一個匹配的模板函數並調用它。
• 若上面兩條都失敗,則使用函數重載的方法,通過類型轉換產生參數匹配,若找到就調用它。
•若上面三條都失敗,還沒有找都匹配的函數,則這個調用是一個錯誤的調用。
在前期做了一份sort(),qsort()的用法分析,鏈接如下:
http://blog.csdn.net/zzzmmmkkk/archive/2009/06/13/4266888.aspx
但是qsort()需要自己編寫一個比較器函數,同時不支持C++集合類,那麼就可以自己編寫一個模板函數來實現.
4.排序函數模板的實現
該函數模板使用冒泡法對集合元素進行排序,參數說明:
collection 集合對象,集合對象必須提供 [] 操作。
element 集合元素,該參數的作用僅僅是確定集合元素類型,參數的值沒有用,建議取集合的第一個元素。集合元素必須提供複製、賦值和比較操作。
count 集合元素的數目
ascend 表明排序時使用升序(true)還是降序(false)
該函數模板支持C++數組以及MFC集合CStringArray、CArray。
代碼如下:
template <typename COLLECTION_TYPE,typename ELEMENT_TYPE>
void BubbleSort(COLLECTION_TYPE collection[],ELEMENT_TYPE element,int count,bool ascend=true)
{
int j,element_flag;
int k=count-1;
while(k>0)
{
element_flag=0;
for(j=element;j<k;j++)
{
if(ascend)
{
if(collection [j] > collection [j+1])
{
COLLECTION_TYPE temp=collection [j];
collection [j] = collection [j+1];
collection [j+1] = temp;
element_flag=j;
}
}
else
{
if(collection [j] < collection [j+1])
{
COLLECTION_TYPE temp=collection [j];
collection [j] = collection [j+1];
collection [j+1] = temp;
element_flag=j;
}
}
}
k=element_flag;
}
}
利用它對整型數組進行排序,
int ArrayInt[]={29,12,4,34,56,0,8,6,18,32};
BubbleSort(ArrayInt,0,10,false);//如果省去false講按默認的true排列
對整數集合按升序排序:
CArray <int, int> collectionInt;
collectionInt.Add(34);
collectionInt.Add(90);
collectionInt.Add(6);
collectionInt.Add(91);
collectionInt.Add(37);
collectionInt.Add(21);
collectionInt.Add(187);
BubbleSort(collectionInt, collectionInt[0],collectionInt.GetSize());
對字符串數組的排列:
string arrayString[4] = {"jackjones", "lee", "levi's","boss"};
BubbleSort(arrayString,0,4,false);
對一個字符串集合按降序排序:
CStringArray collectionString;
collectionString.Add("jackjones");
collectionString.Add("lee");
collectionString.Add("levi's");
collectionString.Add("boss");
BubbleSort(collectionString, collectionString[0],
collectionString.GetSize(), false);