目錄
- 目錄
- 前言
- 模闆概述
- 函數模闆
- 函數模闆文法
- 函數模闆遇上函數重載
- 函數模闆原理概述
- 總結
前言
從接觸到泛型程式設計都現在決定寫部落格,不知道過去多久的時間,感覺每次記得,然後每次都會忘記,是以沒有記錄的工作,基本等于沒做。。某句話就是,一旦你今天想要完成的事情沒有完成,或許你永遠不會再完成它了!
學習!分享!感謝!
模闆概述
函數模闆實際上是建立一個通用函數,其函數類型和形參類型不具體指定,用一個虛拟的類型來代表。這個通用函數就稱為函數模闆。凡是函數體相同的函數都可以用這個模闆來代替,不必定義多個函數,值需要在模闆中定義一次即可。在調用函數時系統會根據實參的類型來取代模闆中的虛拟類型,進而實作不同函數的功能。
C++提供兩種模闆機制:函數模闆和類模闆。類型參數化使得程式可以從邏輯功能上抽象,把被處理的對象(資料)類型作為參數傳遞。
總結:模闆把函數或類要處理的資料類型參數化,表現為參數的多态性,稱為類屬;模闆用于表達邏輯結構相同,但具體資料元素類型不同的資料對象的通用行為。
函數模闆
比如要交換分别char、int、double類型的變量的值,對于函數功能是相同的,但是參數是不同的。也就是說函數功能和資料類型相分離。
函數模闆文法
函數模闆定義形式:
template <類型形式參數表>
類型形式參數的形式為:
typename T1, typename T2, typename Tn
或
class T1, class T2, class T3
函數模闆聲明:
template <類型形式參數表>
類型 函數名(形式參數表)
{
語句序列
}
函數模闆定義有模闆說明和函數定義組成
模闆說明的類屬參數必須在函數定義中至少出現一次
函數參數表中可以使用類屬類型參數,也可以使用一般類型參數
函數模闆在使用的時候可以做自動類型推導,也可以顯示調用
#include <iostream>
template <typename T>
T max(T a, T b)
{
return a>b?a:b;
}
void main()
{
max(, ); // 自動推導
max<int>(,); // 顯式調用
max('y', 'e');
}
- 舉例
template <typename T1, typename T2>
int mySort(T1 *array, T2 size)
{
T1 tmp;
T2 i, j;
if(array == NULL)
{
return -;
}
for(i=; i<size; i++)
{
for(j=i+; j<size; j++)
{
if(array[i] < array[j])
{
tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
}
}
return ;
}
template <typename T1, typename T2>
int myPrint(T1 *array, T2 size)
{
T2 i;
for(i=; i<size; i++)
{
cout << array[i] << endl;
}
return ;
}
int main(void)
{
int myArray[] = {, , , , , , , , };
int size = sizeof(myArray)/sizeof(myArray[]);
mySort<int, int>(myArray, size);
cout << "after sort" << endl;
myPrint<int, int>(myArray, size);
char myCharArray[] = "liuqiang-simon";
size = strlen(myCharArray);
mySort<char, int>(myCharArray, size);
cout << "after sort" << endl;
myPrint<char, int>(myCharArray, size);
}
函數模闆遇上函數重載
- 函數模闆和普通函數差別結論:
- 函數模闆不允許自動類型轉換,具有嚴格的類型比對。
- 普通函數能夠進行自動類型轉換
注意:重寫發生在父類和子類之間,重載發生在同一個作用域。虛函數重寫産生多态;不是虛函數重寫,産生函數重定義,此時父類所有的函數名相同的函數都不能運作。
- 函數模闆和普通函數在一起,調用規則:
- 函數模闆可以像普通函數一樣被重載(參數個數 參數類型 參數順序)
- C++編譯器優先考慮普通函數
- 如果函數模闆可以産生一個更好的比對,那麼選擇模闆
- 可以通過空模闆實參清單的文法限定編譯器隻通過模闆比對
- 舉例
#include <iostream>
using namespace std;
int Max(int a, int b)
{
cout<<"int Max(int a, int b)"<<endl;
return a > b ? a : b;
}
// 模闆
template<typename T>
T Max(T a, T b)
{
cout<<"T Max(T a, T b)"<<endl;
return a > b ? a : b;
}
template<typename T>
T Max(T a, T b, T c)
{
cout<<"T Max(T a, T b, T c)"<<endl;
return Max(Max(a, b), c);
}
void main()
{
int a=, b=;
cout<<Max(a, b)<<endl; // 當函數模闆和普通函數都符合調用時,優先選擇普通函數
cout<<Max<>(a, b)<<endl; // 若顯式使用函數模闆,則使用<>類型清單
cout<<Max(, )<<endl; // 如果函數模闆産生更好的比對,使用函數模闆
cout<<Max(, , )<<endl; // 重載
cout<<Max('a', )<<endl; // 調用普通函數 可以隐式類型轉換
}
函數模闆原理概述
其實函數模闆中,并不是編譯器把函數模闆處理成能夠處理任意類的函數,編譯器隻是從函數模闆中通過具體類型産生不同的函數。據說,編譯器會對函數模闆進行兩次編譯,在聲明的地方對模闆代碼本身進行編譯;在調用的地方對參數替換後的代碼進行編譯。
由這張圖可知,對程式編譯過程進行說明,從中可以知道要進行預處理、編譯、彙編、連結等過程。在編譯的過程中,第一次編譯先對有函數模闆的地方進行标記,在第二次編譯的時候,在用到函數模闆的地方,對函數進行替換成有具體參數類型的函數。
同時記錄下gcc的編譯指令,以前想要總結一下,不過太麻煩而且不會markdown.
總結
上面都所有代碼都是在一個檔案中,但是實際工作中,我們肯定需要把聲明和定義分别放置在頭檔案和源檔案中,這樣才能夠保證工程的整潔。本節主要是對學過的函數模闆機制進行複習。所有内容都來自于《傳智播客掃地僧c++基礎和進階課堂講義.docx》。以後也是對這份文檔的厚顔抄襲!!!
附上《傳智播客掃地僧c++基礎和進階課堂講義.docx》下載下傳位址。