1.函數指針——指針函數
函數指針的重點是指針。表示的是一個指針,它指向的是一個函數,例子:
int (*pf)();
指針函數的重點是函數。表示的是一個函數,它的返回值是指針。例子:
int* fun(); 程序員
其實也能夠經過運算符優先級來判斷,()優先級比*優先級要高。數組
2.數組指針——指針數組
數組指針的重點是指針。表示的是一個指針,它指向的是一個數組,例子:
int (*pa)[8];
指針數組的重點是數組。表示的是一個數組,它包含的元素是指針。例子;
int* ap[8];
3.類模板——模板類(class template——template class)
類模板的重點是模板。表示的是一個模板,專門用於產生類的模子。例子: 函數
template <typename T> class Vector { };
使用這個Vector模板就能夠產生不少的class(類),Vector <int> 、Vector <char> 、Vector < Vector <int> > 、Vector <Shape*> ……。
模板類的重點是類。表示的是由一個模板生成而來的類。例子:
上面的Vector <int> 、Vector <char> 、……全是模板類。
這兩個詞很容易混淆,我看到不少文章都將其用錯,甚至一些英文文章也是這樣。將他們區分開是很重要的,你也就能夠理解爲何在定義模板的頭文件.h時,模板的成員函數實現也必須寫在頭文件.h中,而不能像普通的類(class)那樣,class的聲明(declaration)寫在.h文件中,class的定義(definition)寫在.cpp文件中。工具
array是一個模板,array<int, 50>是一個模板實例 - 一個類型。從array建立array<int, 50>的過程就是實例化過程。實例化要素體如今main.cpp文件中。若是按照傳統方式,編譯器在array.h文件中看到了模板的聲明,但沒有模板的定義,這樣編譯器就不能建立類型array<int, 50>。但這時並不出錯,由於編譯器認爲模板定義在其它文件中,就把問題留給連接程序處理。spa
如今,編譯array.cpp時會發生什麼問題呢?編譯器能夠解析模板定義並檢查語法,但不能生成成員函數的代碼。它沒法生成代碼,由於要生成代碼,須要知道模板參數,即須要一個類型,而不是模板自己。指針
這樣,連接程序在main.cpp 或 array.cpp中都找不到array<int, 50>的定義,因而報出無定義成員的錯誤。code
關於一個缺省模板參數的例子: blog
template <typename T = int> class Array { };
第一次我定義這個模板並使用它的時候,是這樣用的:
Array books;//我認爲有缺省模板參數,這就至關於Array <int> books
上面的用法是錯誤的,編譯不會經過,緣由是Array不是一個類。正確的用法是Array <> books;
這裏Array <> 就是一個用於缺省模板參數的類模板所生成的一個具體類。
4.函數模板——模板函數(function template——template function)
函數模板的重點是模板。表示的是一個模板,專門用來生產函數。例子: ci
template <typename T> void fun(T a) { }
在運用的時候,能夠顯式(explicitly)生產模板函數,fun <int> 、fun <double> 、fun <Shape*> ……。
也能夠在使用的過程當中由編譯器進行模板參數推導,幫你隱式(implicitly)生成。
fun(6);//隱式生成fun <int>
fun(8.9);//隱式生成fun <double>
fun(‘a’);// 隱式生成fun <char>
Shape* ps = new Cirlcle;
fun(ps);//隱式生成fun <Shape*>
模板函數的重點是函數。表示的是由一個模板生成而來的函數。例子:
上面顯式(explicitly)或者隱式(implicitly)生成的fun <int> 、fun <Shape*> ……都是模板函數。
模板自己的使用是很受限制的,通常來講,它們就只是一個產生類和函數的模子。除此以外,運用的領域很是少了,因此不可能有什麼模板指針存在的,即指向模板的指針,這是由於在C++中,模板就是一個代碼的代碼生產工具,在最終的代碼中,根本就沒有模板自己存在,只有模板具現出來的具體類和具體函數的代碼存在。
提醒:在本文的幾個術語中,語言的重心在後面,前面的詞是做爲形容詞使用的。 原型
2 函數模板的異常處理
函數模板中的模板形參可實例化爲各類類型,但當實例化模板形參的各模板實參之間不徹底一致時,就可能發生錯誤,如:
template<typename T> void min(T &x, T &y) { return (x<y)?x:y; } void func(int i, char j) { min(i, i); min(j, j); min(i, j); min(j, i); }
例子中的後兩個調用是錯誤的,出現錯誤的緣由是,在調用時,編譯器按最早遇到的實參的類型隱含地生成一個模板函數,並用它對全部模板函數進行一致性檢查,例如對語句
min(i, j);
先遇到的實參i是整型的,編譯器就將模板形參解釋爲整型,此後出現的模板實參j不能解釋爲整型而產生錯誤,模板函數是沒有隱含的類型轉換功能的。解決此種異常的方法有兩種:
⑴採用強制類型轉換,如將語句min(i, j);改寫爲min(i,int( j));
⑵用非模板函數重載函數模板
方法有兩種:
① 借用函數模板的函數體
此時只聲明非模板函數的原型,它的函數體借用函數模板的函數體。如改寫上面的例子以下:
template<typename T> void min(T &x, T &y) { return (x<y)?x:y; } int min(int,int); void func(int i, char j) { min(i, i); min(j, j); min(i, j); min(j, i); }
執行該程序就不會出錯了,由於重載函數支持數據間的隱式類型轉換。
② 從新定義函數體
就像通常的重載函數同樣,從新定義一個完整的非模板函數,它所帶的參數能夠隨意。
C++中,函數模板與同名的非模板函數重載時,應遵循下列調用原則:
• 尋找一個參數徹底匹配的函數,若找到就調用它。若參數徹底匹配的函數多於一個,則這個調用是一個錯誤的調用。
• 尋找一個函數模板,若找到就將其實例化生成一個匹配的模板函數並調用它。
• 若上面兩條都失敗,則使用函數重載的方法,經過類型轉換產生參數匹配,若找到就調用它。
•若上面三條都失敗,尚未找都匹配的函數,則這個調用是一個錯誤的調用。
3.函數模板與類模板有什麼區別?
答:函數模板的實例化是由編譯程序在處理函數調用時自動完成的,而類模板的實例化必須由程序員在程序中顯式地指定。
即函數模板容許隱式調用和顯式調用而類模板只能顯示調用