1. 程式人生 > >C++程式設計案例教程——Cha8 模板和STL 總結

C++程式設計案例教程——Cha8 模板和STL 總結

    模板是C++的一個語言特性,是實現引數多型的方法,也是C++實現泛型程式設計的重要機制。模板使程式設計使可以快速建立具有型別安全的類庫和函式的集合。函式中的引數多型稱為函式模板,類中的引數多型稱為類模板,而STL標準模板庫也正式成為標準C++庫的一部分,提供了資料結構和演算法。

  • 8.1 模板簡介     程式設計過程中會出現針對不同類的資料型別要進行完全相同的操作,通過模板這種機制將所定義的函式或者類中的部分資料的型別作為引數定義,在使用時通過實參來確定真正的型別。這就是引數化多型。
  • 8.2函式模板
int Max(int a, int b)
{
	return a>b?a:b;
}
int Max(double a,double b)
{
	return a>b?a:b;
}

將上述函式中的型別引數化就是將int 和double 用引數Type來替代,得到如下通用程式碼:

Type Max(Type a,Type b)

{
	return a>b?a:b;
}

當使用函式求兩個整數或實數的最大值時,只需要將Type換成int或double即可。使用通用程式碼後,可使用的引數型別不僅限於int和double,可以是任意數值型別。

C++中使用關鍵字template定義模板,格式如下:

template<模板引數表>
函式定義

模板引數表中的內容為:

class 識別符號 或 typename 識別符號(至少1個)

當上述引數表包含多個引數時,各項之間用逗號隔開。標準C++建議使用typename。上述引數化的函式稱為函式模板。函式模板不是函式,只是一個函式的樣板。只有型別引數例項化後才會生成所要使用的函式。函式模板的使用和一般函式使用完全相同。

函式名(實參表)

例8.1函式模板的使用

include<iostream>
using namespace std;
template <typename T>
T Max(T a,T b)
{
	return  a>b?a:b;
}
int main()
{
	int i=1,j=2;
	double m=0.2,n=0.3;
	imax=Max(i,j);
	dmax=Max(m,n);
	cout<<"imax="<<imax;
	cout<<"dmax="<<dmax;
	rerturn 0;
}

  編譯器編譯上述程式時;會呼叫根據Max()所呼叫的實參推匯出函式模板的型別引數,並使用推導所得的型別代替函式模板中的型別T。

  • 8.3類模板 8.3.1類模板的定義   類模板不是一個具體的類,而是類的一個模板。使用類模板可以生成類的型別,類模板例項化的到一個模板類。模板類才是真正的類,用它定義物件,然後使用物件的成員函式。   類模板宣告格式如下:
template<類模板引數>
類宣告

其中類模板引數表中內容:

template <識別符號> 或 class <識別符號>  
或
<型別表示式>  <識別符號>

    第一種<識別符號>是引數化型別名,第二種<識別符號>是則代表類宣告所宣告類中引數化的常量,<型別表示式> 規定了常量的型別。當模板引數表中同時包含上述多個引數時,引數之間用逗號隔開。    類模板只有在使用時的時候才具體化為具體的類型別。模板類使用物件時,按如下形式宣告:

類模板名<模板引數表> <物件名1>,...,<物件名n>

例:有越界檢查功能的陣列定義如下:

template<typename T>    //array.h
class Array<T>
{
	public:
		Array(int s);
		virtual ~Array();
		int Getsize()const;
		T& operator[](int);
	private:
	   int size;
	   T * element;
};
template<typename T>
Array<T>::Array(int s)
{
	size=s;
	element= new T[size];
}
template<typename T>
Array<T>::~Array()
{
	delete [ ] element;
}
template<typename T>
T & Array<T>::operator[ ] (int i)
{
	if(i<0||i>=size)
	{
		cout<<"下標越界"<<endl;
		exit(1);
	}
	return element[i];
}
說明:(1)類模板聲明瞭一個引數化的型別T,用在成員和成員函式的宣告中。
	 (2)因為這些函式都是類模板的成員函式,該類的模板名字是Array<T>,所以每個成員函式名前都加上Array<T>。

類模板的使用

#include<iostream>
#include"array.h"
using namespace std;
int main()
{
	Array <int>  a(5);
	int i;
	cin>>i;
	a[i]=1;
	cout<<a[i];
	return 0;
}

程式執行結果:

8
下標越界
說明:(1)使用類模板生成一個特定的類時,需要指定引數T所代表的型別。例如:Array <int>  聲明瞭一個員型別為int的陣列類。
     (2)編譯器遇到型別表示式:Array <int>,通過將T替換成int生成所需要的類。

8.3.2 類模板用作函式的引數 類模板用作函式模板的引數使用

#include<iostream>
#include"array.h"
using namespace std;
template<typename T>
void F(Array <T> & t,int i)
{
	cout<<t[i]<<endl;
}
int main()
{
	Array <int>  a(10);
	int i;
	cin>>i;
	a[5]=i;
	F(a,5);
	return 0;
}

編譯期間,編譯器通過推導將F(a,5)由函式模板生成如下模板函式:

void F(Array < int >  &a,int i);

8.3.3 類模板用作基類   對前面陣列進行改進,使得陣列下標不再是由“0”,而是有指定值開始。同時為了是定義陣列不在受型別的限制,將陣列實現為類模板,通過繼承的方法可以實現需要的類模板。

#include"array.h"      //barray.h
template <typename T>
class bArray:public Array <T>
{
	public:
		bArray(int s,int b=0);
		T& operator[ ](int);
	private:
	    int min();
};
template <typename T>
bArray < T >:: bArray (int s,int b):Array<T>:Array<T>(s)
{
	min=b;	
}
template <typename T>
T & bArray <T>::operator [ ] (int i)
{
	return Array <T>::operator [ ]( i-min);
}
說明:(1)Array <T>是bArray < T >的基類,在bArray < T >建構函式的初始化列表中使用了表示式Array<T>(s)以呼叫基類的建構函式。
	(2) 為了實現基類成員函式使用了Array <T>::operator [ ]( i-min)
  • 8.4 STL   C++標準模板庫(STL)包含容器、演算法和迭代字,容器包括連結串列、向量、對列、結合、對映等;演算法模板包括排序、查詢等各種演算法;迭代子可以在不同容器上操作。 8.4.1 STL簡介   STL容器是基於模板機制的,其中包括線性容器和非線性容器。主要容器有:vector(向量模板)、list(列表模板)、stack(棧模板)、queue(對列模板)、deque(雙端對列模板)、map(對映模板)。   迭代子可以方便訪問STL中容器中的物件。STL中的迭代子可以看成指標的推廣。迭代子有順序訪問和直接訪問,分別對應順序訪問容器和直接訪問容器。   STL的演算法是函式模板實現的,可以使用演算法通過迭代子實現對不同型別物件的通用操作。演算法與容器之間是通過迭代子進行溝通的,演算法面向迭代子,迭代子面向容器。通過迭代子可以獲得容器內部的資料物件,演算法對這個由迭代子獲得的物件進行操作。STL中的演算法主要有:排線、查詢、比較和統計。 8.4.2容器   容器是一種面向物件的資料結構表示的方法。C++中的陣列可以看成一種內建的容器。C++提供了使用者自己定義相關容器類的機制。   容器類分為線性和非線性兩大類。線性容器中元素是有序的,非線性容器中元素是無序的。   以向量容器為例,向量可以對內部物件進行直接訪問,也可以像連結串列一樣對容器內部的物件進行順序訪問。因為向量具有動態特性,向量容器的大小可以動態增長。向量模板中重要成員函式模板如下: begin():返回指向向量第一個元素的迭代子。 end():返回指向向量最後一個元素後位置的迭代子。 push_back():是指在向量尾部新增元素。 erase():刪除向量任意位置上的元素。 8.4.3迭代子   可以看成指標的擴充套件,與指標類似,用於指向容器中的元素。迭代子對每種容器都有一個實現,作用在不同容器的迭代子也有不同型別,不同迭代子所支援的操作也不盡相同。但是間接引用運算子“ * ”直接應用一個迭代子,這樣可以使用它所指向的元素。   迭代子為訪問容器中的元素提供了除指標之外的一種替代方法。迭代子將容器中的元素抽象為一個序列,為後面的演算法提供了一個容器的通用介面,同時迭代子提供了一個數據訪問的標準模型。也緩解了要求容器提供一組更廣泛操作的壓力。 8.4.4演算法   容器解決的是儲存問題也就是資料結構的問題,但是標準容器只定義了很少的基本操作,所以要標準庫提供更多操作。標準庫中的演算法稱為泛型演算法,稱為演算法是因為它們實現共同的操作;稱為泛型是因為它們可操作在多種容器型別上,既包括內建型別、標準庫中的型別和使用者自定義的與標準庫相容的容器型別。