C++模板和泛型程序設(shè)計
泛型程序設(shè)計(generic programming)是一種算法在實現(xiàn)時不指定具體要操作的數(shù)據(jù)的類型的程序設(shè)計方法瘫辩。所謂“泛型”终吼,指的是算法只要實現(xiàn)一遍抡柿,就能適用于多種數(shù)據(jù)類型冲甘。泛型程序設(shè)計方法的優(yōu)勢在于能夠減少重復(fù)代碼的編寫捷雕。
泛型程序設(shè)計的概念最早出現(xiàn)于 1983 年的 Ada 語言湾蔓,其最成功的應(yīng)用就是 C++ 的標(biāo)準(zhǔn)模板庫(STL)瘫析。也可以說,泛型程序設(shè)計就是大量編寫模板默责、使用模板的程序設(shè)計贬循。泛型程序設(shè)計在 C++ 中的重要性和帶來的好處不亞于面向?qū)ο蟮奶匦浴?/p>
在 C++ 中,模板分為函數(shù)模板和類模板兩種桃序。熟練的 C++ 程序員杖虾,在編寫函數(shù)時都會考慮能否將其寫成函數(shù)模板,編寫類時都會考慮能否將其寫成類模板媒熊,以便實現(xiàn)重用奇适。
C++函數(shù)模板(模板函數(shù))詳解
面向?qū)ο蟮睦^承和多態(tài)機(jī)制有效提高了程序的可重用性和可擴(kuò)充性。在程序的可重用性方面芦鳍,程序員還希望得到更多支持滤愕。舉一個最簡單的例子,為了交換兩個整型變量的值怜校,需要寫下面的 Swap 函數(shù):
void Swap(int & x, int & y)
{
int tmp = x;
x = y;
y = tmp;
}
為了交換兩個 double 型變量的值,還需要編寫下面的 Swap 函數(shù):
void Swap (double & xr double & y)
{
double tmp = x;
x = y;
y = tmp;
}
如果還要交換兩個 char 型變量的值注竿,交換兩個 CStudent 類對象的值……都需要再編寫 Swap 函數(shù)茄茁。而這些 Swap 函數(shù)除了處理的數(shù)據(jù)類型不同外,形式上都是一樣的巩割。能否只寫一遍 Swap 函數(shù)裙顽,就能用來交換各種類型的變量的值呢?繼承和多態(tài)顯然無法解決這個問題宣谈。因此愈犹,“模板”的概念就應(yīng)運(yùn)而生了。
程序設(shè)計語言中的模板就是用來批量生成功能和形式都幾乎相同的代碼的闻丑。有了模板漩怎,編譯器就能在需要的時候,根據(jù)模板自動生成程序的代碼嗦嗡。從同一個模板自動生成的代碼勋锤,形式幾乎是一樣的。
函數(shù)模板的原理
C++ 語言支持模板侥祭。有了模板叁执,可以只寫一個 Swap 模板茄厘,編譯器會根據(jù) Swap 模板自動生成多個 Sawp 函數(shù),用以交換不同類型變量的值谈宛。
在 C++ 中次哈,模板分為函數(shù)模板和類模板兩種。函數(shù)模板是用于生成函數(shù)的吆录,類模板則是用于生成類的窑滞。
函數(shù)模板的寫法如下:
template <class 類型參數(shù)1, class類型參數(shù)2, ...>
返回值類型 模板名(形參表)
{
函數(shù)體
}
其中的 class 關(guān)鍵字也可以用 typename 關(guān)鍵字替換,例如:
template <typename 類型參數(shù)1, typename 類型參數(shù)2, ...>
函數(shù)模板看上去就像一個函數(shù)径筏。前面提到的 Swap 模板的寫法如下:
template <class T>
void Swap(T & x, T & y)
{
T tmp = x;
x = y;
y = tmp;
}
T 是類型參數(shù)葛假,代表類型。編譯器由模板自動生成函數(shù)時滋恬,會用具體的類型名對模板中所有的類型參數(shù)進(jìn)行替換聊训,其他部分則原封不動地保留。同一個類型參數(shù)只能替換為同一種類型恢氯。編譯器在編譯到調(diào)用函數(shù)模板的語句時带斑,會根據(jù)實參的類型判斷該如何替換模板中的類型參數(shù)。
例如下面的程序:
1. #include <iostream>
2. u[sin](http://c.biancheng.net/ref/sin.html)g namespace std;
3. template<class T>
4. void Swap(T & x, T & y)
5. {
6. T tmp = x;
7. x = y;
8. y = tmp;
9. }
10. int main()
11. {
12. int n = 1, m = 2;
13. Swap(n, m); //編譯器自動生成 void Swap (int &, int &)函數(shù)
14. double f = 1.2, g = 2.3;
15. Swap(f, g); //編譯器自動生成 void Swap (double &, double &)函數(shù)
16. return 0;
17. }
編譯器由模板自動生成函數(shù)的過程叫模板的實例化勋拟。由模板實例化而得到的函數(shù)稱為模板函數(shù)勋磕。在某些編譯器中,模板只有在被實例化時敢靡,編譯器才會檢查其語法正確性挂滓。如果程序中寫了一個模板卻沒有用到,那么編譯器不會報告這個模板中的語法錯誤啸胧。
C++類模板(模板類)詳解
人們需要編寫多個形式和功能都相似的函數(shù)赶站,因此有了函數(shù)模板來減少重復(fù)勞動;人們也需要編寫多個形式和功能都相似的類纺念,于是 C++引人了類模板的概念贝椿,編譯器從類模板可以自動生成多個類,避免了程序員的重復(fù)勞動陷谱。
C++ 中類模板的寫法如下:
template <類型參數(shù)表>
class 類模板名{
成員函數(shù)和成員變量
};
類型參數(shù)表的寫法如下:
class類塑參數(shù)1, class類型參數(shù)2, ...
類模板中的成員函數(shù)放到類模板定義外面寫時的語法如下:
template <類型參數(shù)表>
返回值類型 類模板名<類型參數(shù)名列表>::成員函數(shù)名(參數(shù)表)
{
...
}
用類模板定義對象的寫法如下:
類模板名<真實類型參數(shù)表> 對象名(構(gòu)造函數(shù)實際參數(shù)表);
如果類模板有無參構(gòu)造函數(shù)烙博,那么也可以使用如下寫法:
類模板名 <真實類型參數(shù)表> 對象名;
類模板看上去很像一個類。下面以 Pair 類模板為例來說明類模板的寫法和用法烟逊。
實踐中常常會碰到渣窜,某項數(shù)據(jù)記錄由兩部分組成,一部分是關(guān)鍵字焙格,另一部分是值图毕。關(guān)鍵字用來對記錄進(jìn)行排序和檢索,根據(jù)關(guān)鍵字能查到值眷唉。例如予颤,學(xué)生記錄由兩部分組成囤官,一部分是學(xué)號,另一部分是績點(diǎn)蛤虐。要能根據(jù)學(xué)號對學(xué)生進(jìn)行排序党饮,以便方便地檢索績點(diǎn),則學(xué)號就是關(guān)鍵字驳庭,績點(diǎn)就是值刑顺。
下面的Pair類模板就可用來處理這樣的數(shù)據(jù)記錄:
1. #include <iostream>
2. #include <string>
3. u[sin](http://c.biancheng.net/ref/sin.html)g namespace std;
4. template <class T1,class T2>
5. class Pair
6. {
7. public:
8. T1 key; //關(guān)鍵字
9. T2 value; //值
10. Pair(T1 k,T2 v):key(k),value(v) { };
11. bool operator < (const Pair<T1,T2> & p) const;
12. };
13. template<class T1,class T2>
14. bool Pair<T1,T2>::operator < (const Pair<T1,T2> & p) const
15. //Pair的成員函數(shù) operator <
16. { //"小"的意思就是關(guān)鍵字小
17. return key < p.key;
18. }
19. int main()
20. {
21. Pair<string,int> student("Tom",19); //實例化出一個類 Pair<string,int>
22. cout << student.key << " " << student.value;
23. return 0;
24. }
程序的輸出結(jié)果是:
Tom 19
實例化一個類模板時,如第 21 行饲常,真實類型參數(shù)表中的參數(shù)是具體的類型名蹲堂,如 string、int 或其他類的名字(如 CStudent)等贝淤,它們用來一一對應(yīng)地替換類模板定義中“類型參數(shù)表”中的類型參數(shù)柒竞。類模板名 <真實類型參數(shù)表>就成為一個具體的類的名字。
編譯器編譯到第 21 行時播聪,就會用 string 替換 Pair 模板中的 T1朽基,用 int 替換 T2,其余部分原樣保留离陶,這樣就自動生成了一個新的類稼虎。這個類的名字編譯器是如何處理的不需要知道,可以認(rèn)為它的名字就是 Pair <string, int>招刨。也可以說霎俩,student 對象的類型就是 Pair<string, int>。
Pair<string, int> 類的成員函數(shù)自然也是通過替換 Pair 模板的成員函數(shù)中的 T1沉眶、T2 得到的茸苇。
編譯器由類模板生成類的過程叫類模板的實例化。由類模板實例化得到的類叫模板類沦寂。