項(xiàng)目地址
課程內(nèi)容
- Part1 C++模板簡(jiǎn)介(An Introduction to C++ Template)
- Part2 泛型編程(Generic Programming)
- Part3 容器(Containers)
- Part4 一些進(jìn)階問(wèn)題(Some Advanced Topic)
Part1 C++模板簡(jiǎn)介
- C++模板概觀(Overview)
- C++函數(shù)模板(Function Template)
- C++類(lèi)模板(Class Template)
- C++操作符重載(Operator Overloading)
C++模板概觀(1)
- 模板(Templates)是C++的一種特性,允許函數(shù)或類(lèi)(對(duì)象)通過(guò)泛型(generic types)的形式表現(xiàn)或運(yùn)行
- 模板可以使得函數(shù)或類(lèi)在對(duì)應(yīng)不同的型別(types)的時(shí)候正常工作,而無(wú)需為每一個(gè)型別都寫(xiě)一份代碼
- 一個(gè)簡(jiǎn)單的例子:
- 如果要寫(xiě)一個(gè)取兩個(gè)數(shù)中較大值的函數(shù)Max,在不使用模板的情況下,我們不得不針對(duì)不同的型別(比如int,long,char)提供每一種型別的重載:
int Max(int a, int b)
{
return (a>b)?a:b;
}
long Max(long a, long b)
{
return (a>b)?a:b;
}
char Max(char a, char b)
{
return (a>b)?a:b;
}
C++模板概觀(2)
- 一個(gè)簡(jiǎn)單的例子(續(xù))
- 如果使用模板,則可以省去一堆亢余代碼,從而將函數(shù)原型縮減到非常簡(jiǎn)介的表達(dá):
template <typename T> T Max(T a, T b)
{
return (a>b)?a:b;
}
- C++主要有兩種類(lèi)型的模板:
- 類(lèi)模版(Class template):使用泛型參數(shù)的類(lèi)(classes with generic parameters)
- 函數(shù)模板(Function template):使用泛型參數(shù)的函數(shù)(functions with generic parameters)
C++模板概觀(3)
- 模板實(shí)例化
- 模板的聲明(declaration)其實(shí)并未給出一個(gè)函數(shù)或類(lèi)的完全定義(definition),只是提供了一個(gè)函數(shù)或類(lèi)的語(yǔ)法框架(syntactical skeletion)
- 實(shí)例化是指從模板構(gòu)建出一個(gè)真正的函數(shù)或類(lèi)的過(guò)程,比如
template <typename T> struct Object {...};
可以用來(lái)構(gòu)建諸如Object<int>,Object<char>,Object<int>,Object<MyClass>等等不同型別的具體事例 - 實(shí)例化有兩種類(lèi)型:
- 顯式實(shí)例化-在代碼中明確指定要針對(duì)哪種型別進(jìn)行實(shí)例化
- 隱式實(shí)例化-在首次使用時(shí)根據(jù)具體情況使用一種合適的型別進(jìn)行實(shí)例化
C++函數(shù)模板(1)
- 什么是函數(shù)模板?
- 函數(shù)模板是參數(shù)化的一族函數(shù)(a family of function)
- 通過(guò)函數(shù)模板,可以定義一系列函數(shù),這些函數(shù)都基于同一套代碼,但是可以作用在不同型別的參數(shù)上
template <typename T>
inline T Max(
const T& a,
const T& b)
{
return (a > b) ? a:b;
}
- 定義函數(shù)模板
- 定義一個(gè)函數(shù)模板,返回兩數(shù)中較大的那個(gè),該函數(shù)有兩個(gè)參數(shù):(a,b)
- 參數(shù)型別未定,以模板參數(shù)T表示
- 模板參數(shù)由關(guān)鍵typename引入
C++函數(shù)模板(2)
- 定義函數(shù)模板(續(xù))
- 也可以使用class替代typename來(lái)定義型別參數(shù)
template <class T> inline T Max(const T& a, const T& b) {
...}
- 從語(yǔ)法上講使用class和使用typename沒(méi)有區(qū)別
- 但從語(yǔ)義上,class可能會(huì)導(dǎo)致誤區(qū),即只有類(lèi)才能作為型別參數(shù);而事實(shí)上T所表達(dá)的意思不僅僅只針對(duì)類(lèi),任何型別都可以
- 請(qǐng)盡量使用typename!
- class可以取代typename,但struct卻不可以,以下寫(xiě)法語(yǔ)法上是錯(cuò)誤的:
//this is wrong!!!
template <struct T> inline T Max(const T& a, const T& b)
{
...
}
C++函數(shù)模板(3)
- 模板函數(shù)的使用
- 調(diào)用Max,用int,float,以及std::wstring作為模板參數(shù)替換T
- 對(duì)于不同的型別,都從模板實(shí)例化出不同的函數(shù)實(shí)體
- 但是不可以使用不同型別的參數(shù)來(lái)調(diào)用Max,因?yàn)榫幾g器在編譯時(shí)已經(jīng)知道Max函數(shù)需要傳遞的型別
int i = 7, j = 30;
_tprintf(TEXT("Max(i,j) = %d\n"), Max(i,j));
double f = -1.8, g = -0.9;
_tprintf(TEXT("Max(f,g) = %f\n"), Max(f,g));
std::wstring s1 = TEXT("mathematics"), s2 = TEXT("math");
_tprintf(TEXT("Max(s1,s2) = %s\n"), Max(s1,s2).c_str());
Max(i,f);//compile error: template parameter 'T' is ambiguous
C++函數(shù)模板(4)
- 模板實(shí)例化
- 用具體型別替代模板參數(shù)T的過(guò)程叫做實(shí)例化(instantiation);從而產(chǎn)生了一個(gè)模板事例
- 一旦使用函數(shù)模板,這種實(shí)例化過(guò)程便由編譯器自動(dòng)觸發(fā)的,不需要額外去請(qǐng)求模板實(shí)例化
- 如果實(shí)例化一種型別,而該型別內(nèi)部并不支持函數(shù)所使用的操作,那么就會(huì)導(dǎo)致一個(gè)編譯錯(cuò)誤,如下所示:
- std::complex并沒(méi)有重載“>”,也就是說(shuō)改型別并不支持使用“>”比較大小,而Max函數(shù)使用“>”來(lái)判斷c1,c2的大小,所以無(wú)法通過(guò)Max(c1,c2)得到預(yù)期的結(jié)果
std::complex<int> c1(1,2), c2(15,16); //編譯錯(cuò)誤!
C++函數(shù)模板(5)
- 結(jié)論:模板被編譯了兩次
- 沒(méi)有實(shí)例化之前,檢查模板代碼本身是否有語(yǔ)法錯(cuò)誤
- 實(shí)例化期間,檢查對(duì)模板代碼的調(diào)用是否合法
C++函數(shù)模板(6)
參數(shù)推導(dǎo)
模板參數(shù)是有傳遞給模板函數(shù)的實(shí)參決定的
-
不允許自動(dòng)型別轉(zhuǎn)換:每個(gè)T必須嚴(yán)格匹配!
Max(1,2) //OK:兩個(gè)實(shí)參的型別都是int
Max(1,2.0) //ERROR:第一個(gè)參數(shù)型別是int,第二個(gè)參數(shù)型別是double- 一般有兩種處理這種錯(cuò)誤的方法:
- 用static_cast或強(qiáng)制轉(zhuǎn)換參數(shù)型別以使兩者匹配
Max(static_cast<double>(1), 2.0) - 顯式指定T的型別
Max<double>(1,2.0)
- 用static_cast或強(qiáng)制轉(zhuǎn)換參數(shù)型別以使兩者匹配
- 一般有兩種處理這種錯(cuò)誤的方法:
C++函數(shù)模板(7)
- 函數(shù)模板重載
- 函數(shù)模板也可以像普通函數(shù)一樣被重載
- 非模板函數(shù)可以和同名的模板函數(shù)共存
- 編譯器通過(guò)函數(shù)模板參數(shù)推導(dǎo)來(lái)決定使用調(diào)用哪個(gè)重載
//普通函數(shù)
//1
inline int const& Max(const int const& a, const int const& b)
//2
template <typename T>
inline T const& Max(const T const& a, const T const& b)
//3
template <typename T>
inline T const& Max(const T const& a, const T const& b, const T const& c)
C++函數(shù)模板(8)
函數(shù)模板重載(續(xù))
- Max(7, 42, 68):調(diào)用接受三個(gè)參數(shù)的模板 ————3
- Max(7.0, 42.0):調(diào)用Max<double> (參數(shù)推導(dǎo)) ————2
- Max('a', 'b'):調(diào)用Max<char> (參數(shù)推導(dǎo)) ————2
- Max(7, 42):調(diào)用非模板函數(shù),參數(shù)型別為int ————1 其他因素都相同的情況下,重載裁決過(guò)程調(diào)用非模板函數(shù),而不是從模板產(chǎn)生實(shí)例
- Max<>(7, 42):調(diào)用Max<int> (參數(shù)推導(dǎo)) ————2 允許空模板參數(shù)列表
- Max<double>(7, 42): 調(diào)用Max<double> (無(wú)需參數(shù)推導(dǎo)) ————2
- Max('a', 42.7):調(diào)用非模版函數(shù),參數(shù)型別為int ————1 對(duì)于型別不同的 參數(shù)只能調(diào)用非模版函數(shù)(char型別'a'和double型別42.7都將轉(zhuǎn)化為int型別)
C++函數(shù)模板(9)
- 總結(jié)
- 對(duì)于不同的實(shí)參型別,模板函數(shù)定義了一族函數(shù)
- 當(dāng)傳遞模板實(shí)參的時(shí)候,函數(shù)模板依據(jù)實(shí)參的型別進(jìn)行實(shí)例化
- 可以顯式指定模板的實(shí)參型別
- 函數(shù)模板可以重載
- 當(dāng)重載函數(shù)模板時(shí),將改變限制在:顯式指定模板參數(shù)
- 所有的重載版本的聲明必須位于它們被調(diào)用的位置之前