OOP筆記(七) 模板與STL

OOP筆記(七) 模板與STL

1.函數模板

(1)泛型程序設計:Generic Programming,算法實現時不指定具體要操作的數據的類型
泛型 — 算法實現一遍->適用於多種數據結構

模板定義的語法格式如下:
在這裏插入圖片描述
例:swap函數

template <class T>
void Swap(T & x, T & y)
{
	T tmp = x; 
	x = y;
	y = tmp;
}
int main()
{
	int n = 1, m = 2;
	swap(n,m);    //(1)編譯器自動生成 void Swap(int &, int &)函數
	//(1)n,m類型確定了模板參數類型int
	cout<<"swap;n="<<n<<"; m="<<m<<endl;  
	double a=3.45,b=6.76;
	swap(a,b);    //(2)編譯器自動生成 void Swap(double &, double &)函數
	//(2)a,b類型確定了模板參數類型double
	cout<<"swap;a="<<a<<"; b="<<b<<endl;
	return 1;
}

(2)函數模板中可以有不止一個類型參數
在這裏插入圖片描述
(3)顯示指定模板函數變量類型
語法: 函數名<可變類型參數列表>(實參表);
在函數調用時,可以顯式地指定模板參數代表的數據類型,

int main()
{
	double x=2.5461;
	string str="hello";
	print<double,string>(x,str);
}

在這裏插入圖片描述
(4)非類型模板參數
【注意】
1)整型,指針和引用才能作爲非類型形參;
2)而且綁定到該形參的實參必須是常量表達式,即編譯期就能確認結果。

template <class T1,int M> //int M非類型參數
T1 *CreateVector()
{
	T1 *p=new T1[M];
	return p; 
}
template <class T1>
void DeleteVector(T1 *p)
{ 
	delete []p; 
}
int main()
{ 
	int *p=CreateVector<int,5>();  //創建整型數組
  	cout<<"Input 5 int numbers:";  
  	for(int i=0;i<5;i++) 
 	{ 
  		cin>>p[i];
  		cout<<setw(5)<<p[i]; 
  	}
  	cout<<endl;
  	DeleteVector(p);
return 1;
} 

(5)函數模板可以重載, 只要它們的形參表不同即可
(6)函數模板調用順序
在這裏插入圖片描述
在這裏插入圖片描述

類模板

1.如果程序中希望一個類的數據成員的類型不侷限爲某一個具體類型,或者希望某個成員函數的參數或 返回值的類型不侷限爲某一個具體類型,就應該把這 樣的類定義爲類模板。類模板不代表具體的實際的類, 而是代表一類類。
在這裏插入圖片描述
類模板的定義:
語法:
template <class 類型參數表,…>
class 類模板名
{
成員函數和成員變量
};
類型參數表列表的寫法就是:
class 類型參數1, class 類型參數2, …
在這裏插入圖片描述
3、C++類模板定義
類模板裏的成員函數, 如在類模板外面定義時,
template <class 類型參數表>
返回值類型 類模板名<類型參數名列表>::成員函數名(參數表)
{……}
4、C++類模板創建對象
用類模板定義對象的寫法如下:
類模板名 <真實類型參數表> 對象名(構造函數實際參數表);
如果類模板有無參構造函數, 那麼也可以只寫:
類模板名 <真實類型參數表> 對象名;

#include<iostream> 
#include<iomanip>
using namespace std;
//定義類模板
template<class T, int maxlen>
//類型參數爲T,最大長度爲maxlen 
class Array
{ 
	private:
	T *data;
	int len;//數組實際長度
	public:
	Array();//(1)構造函數
	~Array();// (2)析構函數
	int getLen() const { return len; }
	// (3)返回實際長度
	void DelArray(int i); 
	// (4)刪除某下標內容
	void InsArray(int i,T x); 
	// (5)在某位置加入數據
	void AddArray(T x); 
	// (6)在最末位置加入數據
	T & operator[](int i) ;
	// (7)重載運算符[]
};

//成員函數類外定義
template<class T,int maxlen> 
Array<T, maxlen>::Array() ()
// (1)構造函數
{
	if(maxlen>0) 
	data=new T[maxlen]; 
	else data=NULL;
	len=0;
}
template<class T,int maxlen>
// (2)析構函數 
Array<T,maxlen>::~Array()
{
	if(data!=NULL) 
	delete []data;
}
template<class T,int maxlen>
void Array<T,maxlen>::DelArray(int i)
{// (4)刪除下標爲i的元素
	if(len<=0) 
	return;
	for(int j=i+1;j<len;j++) 
	data[j-1]=data[j]; 
	len--;
}
T & Array<T,maxlen>::operator[](int i) // (7)重載運算符[]
{//返回第i個元素
	if(i>=0||i<len)
	return data[i];
}
//成員函數類外定義
template<class T,int maxlen>
void Array<T,maxlen>::InsArray(int i,T x)// (5)在下標 i處添加 x
{ 
	if(len>=maxlen||i<0||i>len) 
	return;
	for(int j=len-1;j>=i;j--) 
	data[j+1]=data[j]; 
	data[i]=x;
	len++;
}
template<class T,int maxlen>
void Array<T,maxlen>::AddArray(T x)
{// (6)末尾增加數據
 	InsArray(len,x);
}

//main函數中進行類模板實例化
int main()//
{ 
	int i,m;
	const int n=8; 
	Array<int,n> a;// (1)用int替換類型參數T,將類模板Array實例化爲對象a a是一個int數組
	m=5;
	cout<<"Input "<<m<<" integer numbers:"<<endl; 
	for(i=0;i<m;i++) 
	cin>>a[i]; 
	//(7)調用運算符重載函數[]
	for(i=0;i<a.getLen();i++) 
	//(3)調用getLen()獲取長度
	cout<<setw(6)<<a[i]; 
	cout<<endl;
	a.DelArray(3);
	//(4)調用DelArray刪除下標爲3的元素
	for(i=0;i<a.getLen();i++) 
	cout<<setw(6)<<a[i]; //遍歷顯示數據
	cout<<endl;
	a.InsArray(2,-111);
	//(5)在下標爲2的地方插入-111
	a.AddArray(999);
	//(6)在數組尾部添加999
	for(i=0;i<a.getLen();i++) 
	cout<<setw(6)<<a[i]; cout<<endl;
	return 1;
}

5、類模板的實例化
編譯器由類模板生成類的過程叫類模板的實例化
• 編譯器自動用具體的數據類型, 替換類模板中的類型參數, 生成模板類的代碼,例如:
Array<int,8>
由類模板實例化得到的類叫模板類
•爲類型參數指定的數據類型不同, 得到的模板類不同

關於類模板的幾點說明:
(1) 類模板名:Array<T, maxlen> (代表一族類)
(2) 模板類名:Array<int, 8>
(即類模板的一種實例化,代表一個具體的類)
(3) 類模板在類外定義成員函數的方法:
template <class T, int maxlen> //每個成員函數重複
返回類型 Array<T,maxlen>::成員函數名(形參表)
{ 函數體}
(5)類模板實例化:只有在用模板類名定義對象或對象指針時,編譯程序纔會對類模板進行實例化,生成一個具體的類。
(6)類模板成員函數的實例化:僅發生在用模板類的一個對象或對象指針調用了該成員函數時。
以上類模板實例化的機制表明,僅有類模板的定義,編譯程序不會產生任何目標代碼。
因此,類模板只能以源程序文件形式保存和重用。

6、模板的模板參數
模板的模板參數就是將一個模板作爲另一個模板的參數,也就是說類型形參可以是類模板。

template<int N, template<int> class F>  
class Accumulate  
{
	public:
	enum {RET = Accumulate<N-1,F>::RET + F<N>::RET};  
}; 
template<template<int> class F>  
class Accumulate<0,F>   
{  
	public:
	enum { RET = F<0>::RET };  
};
template<int n>  
class square   
{
	public:
	enum { RET = n*n };  
}; 
int main()  
{  
	cout << "1*1 = "<<Accumulate<1,square>::RET << endl; 
	cout << "1*1+2*2 = "<<Accumulate<2,square>::RET << endl; 
	cout << "1*1+2*2+3*3 = "<<Accumulate<3,square>::RET << endl; 
	cout << "1*1+2*2+3*3+4*4 = "<<Accumulate<4,square>::RET << endl; 
	return 0;  
}

STL

使用模板的程序設計法。
將一些常用的數據結構(比如鏈表,數組) 和算法(比如排序,查找)寫成模板,以後則不論數據 結構裏放的是什麼對象,算法針對什麼樣的對象,則都不必重新實現數據結構,重新編寫算法。
標準模板庫 (Standard Template Library) 就是一 些常用數據結構和算法的模板的集合。

容器:可容納各種數據類型【 基本類型的變量, 對象等 】的通用數據結構,如array(數組)(C++內置不屬於STL)、list(串行)、stack(堆棧)、queue(隊列)等,用來存放數據,從實現角度來看,STL容器是一種class template。
迭代器:可用於依次存取容器中元素,類似於指針,所有STL容器都附帶有自己專屬的迭代器
算法:用來操作(如sort、find、copy、for_each)容器中的元素的,從實現的角度來看,STL算法是一種function tempalte
算法本身與他們操作的數據的類型無關,因此他們可以在從簡單數組到高度複雜容器的任何數據結構上使用。

1、序列式容器之一:vector #include、
容器裏面的數據可以進行排序,但是不會自動排序,可以使用算法進行排序;template class vector;
vector(動態數組):元素在內存連續存放。隨機存取任何元素都能在常數時間完成。在尾端增刪元素具有較佳的性能(大部分情況下是常數時間)。
在這裏插入圖片描述
2、序列式容器之二:list #include
雙向鏈表(double linked-list),迭代器必須具備前移、後移的能力template class list;

3、容器配接器之三:stack和queue
stack、queue沒有迭代器,以list作爲以list作爲queue的底層容器, template<classT, class Cont==deque>class stack;
queue<int, list > iqueue;queue q;

4、容器:vector
vector 的數據安排以及操作方式,與C++中的數組非常相似。
區別在於:
(1)C++中的數組是固定大小的,分配給C++數組的空間數量在數組的生存期內是不會改變的。
( 2 )向量vector是動態結構,它的大小不固定,可以在程序運行時增加或減少。
vector中的元素在內存是連續存儲的,可以直接訪問。
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
例子:

int main()
{
	int i;
	int a[5] = {1,2,3,4,5};
	vector<int>v(5);//初始化5個元素,元素初始值爲0
	cout << v.end()- v.begin() << endl; 
	for( i = 0; i < v.size(); i ++ )  
	v[i] = i; 
	v.at(4) = 100;
	for( i = 0; i < v.size(); i ++ )
	cout << v[i] << "," ; cout << endl;
	vector<int> v2(a,a+5);//構造函數
	v2.insert(v2.begin() + 2,13); //在begin()+2位置插入13
	for( i = 0; i < v2.size(); i ++ )
	cout << v2.at(i) << "," ;
	return 0;
}

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