07-敲開泛型編程的大門

前言

C++原來的名字叫做C with classes(即帶有類的C語言)。而類具有的一大特點就是存在運行期多態,那麼我們就會考慮一個問題,在C++的編譯期可不可以實現多態呢? 其實是可以的,在前面講過的auto中就運用了編譯期的多態的特性。比如這個例子:auto i = 5;在這個例子裏面,i的類型在編譯期就已經確定了,在運行期i的類型就是int了。這種編程方式也叫做泛型編程,泛型編程的一個重要關鍵字template。下面我們就來看看這部分的內容吧。

泛型編程

我們先舉一個例子,你們班有五個同學,小明,小華,小紅,小李,小明,每個人上學的路都是不一樣的。那麼我們需要給出一個上學的函數,計算每個同學到達學校的時間,我們需要給出每個同學出門的標準化時間,和每個同學的相關信息。至於每個函數裏面如何實現我們並不關心,只關心這部分抽象出來的算法,這部分算法就是泛型編程。

所謂泛型編程就是獨立於任何特定類型的方式編寫代碼,使用泛型程序時,需要提供具體陳旭實例所操作的類型或者值。

學習泛型編程就肯定會學習模版編程,下面就來看看C++模版編程有什麼魔力吧。

C++模版

模版定義

下面看一下這個函數:

void print_value_type(int x) {
	cout << "this is a int,value is : " << x << endl;
}

如果我想把這個函數擴大到所有的類型去,那麼我們就需要使用模版這個知識點了。下面來看一下:

template<typename T>
void print_value_type(T x) {
	cout << "this is a " << typeid(T).name() << ",value is : " << x << endl;
}

這就實現了不同類型實現類似操作的功能。

實例化模版

既然定義了C++模版,那麼我就需要對其進行實例化。在實例化中有顯式實例化和隱式實例化,對於上面這個例子來說顯式實例化就是print_value_type<int>(50);隱式實例化print_value_type(50);

儘管C++模版可以實例化很多的實例,但是對於同一個輸入參數只能實例化出一個實例。其實也很容易理解,如果實例化很多實例在運行期調用哪一個實例就成了問題,一旦成了問題那麼系統就會報錯處理。這和C++重載是一樣的,無論你重載多少個函數,我調用的時候必須確定一個函數用於調用。這個時候問題就來了,C++模版的調用順序問題?

  1. 先找參數完全匹配的普通函數(非由模板實例化得到的函數)。
  2. 再找參數完全匹配的模板函數。
  3. 再找實參經過自動類型轉換後能夠匹配的普通函數。
  4. 如果上面的都找不到,則報錯。

如果這個順序下可以確定調用的函數,那麼這個調用就是合法的。

特化模版

上面那種普通的模版聲明方式,如果不能滿足某一類型的要求。比如我們對於vector需要輸出每一個元素,顯然使用簡單的<<不能滿足要求。那麼我們就需要對這一些特殊的類型聲明特殊的操作,如何操作呢?

template<typename T>
void print_value_type(T x) {
	cout << "this is a " << typeid(T).name() << ",value is : " << x << endl;
}
template<>
void print_value_type<vector<int>>(vector<int> x) {
	cout << "this is a " << typeid(int).name() << ",size is : " << x.size() << endl;
	for(auto temp : x)
		cout << temp << " ";
}

當我參數是vector<int>類型時,就會調用這個特化版本。

動態多態和靜態多態

動態多態:是利用虛函數實現了運行時的多態,也就是說在系統編譯的時候並不知道程序將要調用哪一個函數,只有在運行到這裏的時候才能確定接下來會跳轉到哪一個函數的棧幀;

動態多態本質上就是面向對象設計中的繼承、多態的概念。動態多態中的接口是顯式接口

靜態多態:就是在系統編譯期間就可以確定程序執行到這裏將要執行哪個函數。

對於相關的對象類型,直接實現它們各自的定義,不需要共有基類,甚至可以沒有任何關係。只需要各個具體類的實現中要求相同的接口聲明,這裏的接口稱之爲隱式接口

最簡單也最常用的靜態多態就是重載函數。

總結

在C++標準庫裏提供了很多庫函數,這裏我麼就僅僅以sort函數爲例,他對於函數參數的要求如下:

  1. 參數滿足隨機訪問迭代器的要求。
  2. 迭代器指向的對象之間可以使用 < 來比較大小,滿足嚴格弱序關係。
  3. 迭代器指向的對象可以被移動。

**這樣的函數在STL模版中還很多,大家有興趣可以去看一下侯捷老師的《STL源碼分析》,看完你會有很多不一樣的收穫的。這一部分就是帶領大家敲開泛型編程的大門,接下來的幾篇都是關於泛型編程的,有興趣可以繼續關注,希望的我的文章能夠對您有幫助!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章