C++ 泛型基礎

泛型的基本思想:
泛型編程(Generic Programming)是一種語言機制,通過它可以實現一個標準的容器庫。
像類一樣,泛型也是一種抽象數據類型,但是泛型不屬於面向對象,它是面向對象的補充和發展。
在面向對象編程中,當算法與數據類型有關時,面向對象在對算法的抽象描述方面存在一些缺陷。
比如對棧的描述:
class stack
{

push(參數類型) //入棧算法

pop(參數類型) //出棧算法

}
如果把上面的僞代碼看作算法描述,沒問題,因爲算法與參數類型無關。但是如果把它寫成可編譯的源代碼,
就必須指明是什麼類型,否則是無法通過編譯的。使用重載來解決這個問題,即對N種不同的參數類型寫N個
push和pop算法,這樣是很麻煩的,代碼也無法通用。
若對上面的描述進行改造如下:
首先指定一種通用類型T,不具體指明是哪一種類型。
class stack<參數模板 T>
{

push(T) //入棧算法

pop(T) //出棧算法

}

這裏的參數模板T相當於一個佔位符,當我們實例化類stack時,T會被具體的數據類型替換掉。
若定義對象S爲statc類型,在實例化S時若我們將T指定int型則:
這時候類S就成爲:
class S
{
push(int) //入棧算法
pop(int) //出棧算法
}
這時我可以稱class stack<參數模板 T>是類的類,通過它可以生成具體參數類型不同的類。
泛型在C++中的應用:
泛型在C++中的主要實現爲模板函數和模板類。
通常使用普通的函數實現一個與數據類型有關的算法是很繁瑣的,比如兩個數的加法,要
考慮很多類型:
int add(int a,int b) { return a+b; }
float add(float a,float b) { return a+b; }
。。。。
雖然在C++中可以通過函數重載來解決這個問題,但是反覆寫相同算法的函數是比較辛苦的,
更重要的是函數重載是靜態編譯,運行時佔用過多內存。
在此我們可以用C++的模板函數來表達通用型的函數,如下:
template<typename T> // 模板聲明
T add(T a,T b) { return a+b; } // 注意形參和返回值的類型
這時C++編譯器會根據add函數的參數類型來生成一個與之對應的帶具體參數類型的函數並
調用。
例如:
#include <iostream>
using namespace std;
template <typename T>
T add(T a,T b) //注意形參和返回類型
{
return a+b;
}
void main()
{
int num1, num2, sum;
cin>>num1>>num2;
sum=add(num1,num2); //用int匹配模版參數T,若sum,num1,num2類型不一致則無法匹配。
cout<<sum;
}
函數模板的性質
1) 函數模板並不是真正的函數,它只是C++編譯生成具體函數的一個模子。
2) 函數模板本身並不生成函數,實際生成的函數是替換函數模板的那個函數,比如上例中的add(sum1,sum2),
這種替換是編譯期就綁定的。
3) 函數模板不是隻編譯一份滿足多重需要,而是爲每一種替換它的函數編譯一份。
4) 函數模板不允許自動類型轉換。
5) 函數模板不可以設置默認模板實參。比如template <typename T=0>不可以。
C++模版函數的語法
template <typename 模版參數列表…>
函數返回類型 函數名(形參列表…)
上面兩行可以合併成一行。
例如:
下面的幾種寫法是等效的並且class 和typename是可以互換的。
template <typename T1, typename T2>
T1 fun(T1, T2, int )
{ //…..}
template <typename T1,T2> T1 fun(T1, T2, int )
{ //…..}
template <class T1, class T2>
T1 fun(T1, T2, int )
{ //…..}
template <class T1,T2> T1 fun(T1, T2, int )
{ //…..}
C++模版類的語法
template <class 模版參數列表…>
class 類名
{ //類體}
成員的實現…
例如:
//類聲明部分,有兩個模板參數T1,T2
template <class T1, class T2 >
class A {
private:
int a;
T1 b; //成員變量也可以用模板參數
public:
int fun1(T1 x, int y );
T2 fun2(T1 x, T2 y);
}
//類實現部分
template <class T1, class T2 >
int A<T1>:: fun1(T1 x, int y ){//實現…… }
template <class T1, class T2 >
T2 A<T1,T2>:: fun2(T1 x, T2 y) {//實現…… }
//使用類A
int main( ) {
//定義對象a,並用int替換T1, float替換T2
A<int, float> a;
//實例化a,調用a的屬性和方法……
}
由上例可以看出, 類模板參數T1,T2對類的成員變量和成員函數均有效。
在C++編程中,當你要實現的一個類的某些成員函數和成員變量的算法
數據類型有關,可以考慮用類模板。C++版的數據結構算法大都用類模板實現。
類模板的性質
1) 類模板不是真正的類,它只是C++編譯器生成具體類的一個模子。
2) 類模板可以設置默認模板實參。
C++ STL簡介
  STL(Standard Template Library,標準模板庫)是C++對泛型編程思想的實現,最早是惠普實驗室開發的。
在被引入C++之前該技術就已經存在了很長的一段時間。後來STL成爲ANSI/ISO C++標準的一部分。各個
C++廠商也有各自相應的模板庫,這些庫效率可能很高,但可移植性不一定好。
  STL廣義上分爲三類:algorithm(算法)、container(容器)和iterator(迭代器),幾乎所有的代碼都採
用了模板類和模板函數的方式,這相比於傳統的由函數和類組成的庫來說提供了更好的代碼重用機會。
  在C++標準中,STL被組織爲下面的13個頭文件:<algorithm>、<deque>、<functional>、<iterator>、<vector>、
<list>、<map>、<memory>、<numeric>、<queue>、<set>、<stack> 和<utility>。
1) 算法(algorithm)
  STL提供了大約100個實現算法的模版函數,算法部分主要由頭文件<algorithm>,<numeric> 和<functional>組成。
  <algorithm>是所有STL頭文件中最大的一個,它是由一大堆模板函數組成的,其中常用到的功能範圍涉及到比較、
交換、查找、遍歷操作、複製、修改、移除、反轉、排序、合併等等。
  <numeric>體積很小,只包括一些簡單數學運算的模板函數。
  <functional>中則定義了一些模板類,用以聲明函數對象。
2) 容器(container)(又稱集合collection)
  在實際的開發過程中,數據結構本身的重要性不會遜於操作於數據結構的算法的重要性,當程序中存在着對時間要
求很高的部分時,數據結構的選擇就顯得更加重要。
  通過設置一些模版類,STL容器對最常用的數據結構提供了支持,這些模板的參數允許指定容器中元素的數據類
型,可以將許多重複而乏味的工作簡化。
如下表:


數據結構


實現頭文件

向量(vector)

順序性容器

<vector>

列表(list)

順序性容器

<list>

雙隊列(deque)

順序性容器

<deque>

集合(set)

關聯容器

<set>

多重集合(multiset)

關聯容器

<set>

棧(stack)

容器適配器

<stack>

隊列(queue)

容器適配器

<queue>

優先隊列(priority_queue)

容器適配器

<queue>

映射(map)

關聯容器

<map>

多重映射(multimap)

關聯容器

<map>



3)迭代器(iterator)
  迭代器是一種允許程序員檢查容器內元素,並實現元素遍歷的數據類型。C++標準庫爲每一種標準容器定義了一種迭代器類型。迭代器類型提供了比下標操作更一般化的方法:所有的標準庫容器都定義了相應的迭代器類型,而只有少數的容器(比如數組)支持下標操作。因爲迭代器對所有的容器都適用,現代C++程序更傾向於使用迭代器而不是下標操作訪問容器元素。
  迭代器從作用上來說是STL最基本的部分,迭代器在STL中用來將算法和容器聯繫起來,起着一種黏和劑的作用。幾乎STL提供的所有算法都是通過迭代器存取元素序列進行工作的,每一個容器都定義了其本身所專有的迭代器,用以存取容器中的元素。
  迭代器部分主要由頭文件<utility>,<iterator> 和<memory>組成。<utility>是一個很小的頭文件,它包括了貫穿使用在STL中的幾個模板的聲明,<iterator>中提供了迭代器使用的許多方法, <memory>爲容器中的元素分配存儲空間,同時也爲某些算法執行期間產生的臨時對象提供機制,<memory>中的主要部分是模板類allocator,它負責產生所有容器中的默認分配器。


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