1,學習目標
1.理解類模板的概念;
2.掌握類模板的定義、實例化過程,會運用類模板;
3.掌握棧類模板、鏈表類模板的使用;
4.理解STL編程的基本思想;
5.掌握STL容器的使用;
6.熟練使用STL算法;
7.理解STL函數對象;
- 類模板
模板是C++語言的重要特征,它能夠顯著提高編程效率。利用C++的函數模板和類模板,能夠快速建立具有類型安全的類庫集合和函數集合,進行大規模軟件開發,並提高軟件的通用性和靈活性。C++的
標准模板庫(standard template library,簡稱
STL)編程完全依賴模板的實現。
類模板是能根據不同參數建立不同類型成員的類。類模板中的數據成員、成員函數的參數、成員函數的返回值可以取不同類型,在實例化成對象時,根據傳入的參數類型,實例化成具體類型的對象。類模板也稱模板類。
類模板定義的語法為:
template <
模板參數表
>
class
類名
{
成員名;
};
其中:
Ø template為模板關鍵字。
Ø 模板參數表中的類型為參數化(parameterized)類型,也稱可變類型,類型名為class (或typename);模板參數表中的類型也可包含普通類型,普通類型的參數用來為類的成員提供初值。
Ø 類模板中的成員函數可以是函數模板,也可以是普通函數。
例如,下面定義了一個模板類Student,為了增強類的適用性,將學號設計成參數化類型,它可以實例化成字符串、整型等;將成績設計成參數化類型,它可以實例化成整型、浮點型、字符型(用來表示等級分)等;
template <class TNO, class TScore, int num> // TNO,TScore 為參數化類型
class Student
{
private:
TNO StudentID[num]; //參數化類型數組,存儲姓名
TScore score[num]; //參數化類型數組,存儲分數
public:
TNO TopStudent() //普通函數
{
return StudentID[0];
}
int BelowNum(TScore ascore) //函數模板
{
return 0;
}
void sort() //普通函數
{
}
};
模板類的成員函數還可以在類外定義,其語法如下::
template <
模板參數表
>
類型
類名
<
模板參數名表
>
∷函數名
(
參數表
)
{
函數體
;
}
其中:
Ø模板參數表與類模板的模板參數表相同。
Ø模板參數名表列出的是模板參數表中參數名,順序與模板參數表中的順序一致。
模板類Student的成員函數在類外實現如下:
template
<class TNO, class TScore, int num>
class Student
{
private:
TNO StudentID[num];
TScore score[num];
public:
TNO TopStudent();
int BelowNum(TScore ascore);
void sort();
};
template <
class TNO, class TScore, int num
>
int Student<TNO, TScore, num>
::
BelowNum(TScore ascore)
{
return 0;
}
template <class TNO, class TScore, int num>
void Student<TNO, TScore, num>
::
sort()
{
}
template <class TNO, class TScore, int num>
TNO Student<TNO, TScore, num>
::
TopStudent()
{
return StudentID[0];
}
|
一個類模板是具體類的抽象,在使用類模板建立對象時,才根據給定的模板參數值實例化(專門化)成具體的類,然后由類建立對象。與函數模板不同,類模板實例化只能采用顯式方式。
類模板實例化、建立對象的語法如下:
類模板實例化、建立對象的語法如下:
一個類模板是具體類的抽象,在使用類模板建立對象時,才根據給定的模板參數值實例化(專門化)成具體的類,然后由類建立對象。與函數模板不同,類模板實例化只能采用顯式方式。
類模板實例化、建立對象的語法如下:
類模板實例化、建立對象的語法如下:
類模板名
<
模板參數值表
>
對象
1,
對象
2,
…
,
對象
n;
其中:
Ø 模板參數值表的值為類型名,類型名可以是基本數據類型名,也可以是構造數
據類型名,還可以是類類型名。
Ø模板參數值表的值還可以是常數表達式,以初始化模板參數表中普通參數。
Ø模板參數值表的值按一一對應的順序實例化類模板的模板參數表。
class String {
public:
char Str[20];
};
void main()
{
Student<String, float ,100> S1;
S1.sort();
Student<long, int, 50> S2;
S2.TopStudent();
}
class Student
{
private:
String StudentID[100];
float score[100];
public:
String TopStudent();
int BelowNum(float ascore);
void sort();
};
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
// p10_2.cpp * 單向鏈表的類模板 *
#include <iostream>
using namespace std;
template <class TYPE>
class ListNode
{
private:
TYPE data;
ListNode * next;
static ListNode * CurNode;
static ListNode * head;
public:
ListNode()
{
next=NULL;
head=CurNode=this;
}
ListNode(TYPE NewData)
{
data=NewData;
next=NULL;
}
|
2,STL編程
STL(Standard Template Library),即標准模板庫,是一個高效的C++程序庫。STL是ANSI/ISO C++標准函數庫的一個子集,它提供了大量可擴展的類模板,包含了諸多在計算機科學領域里所常用的基本數據結構和基本算法,類似於Microsoft Visual C++中的
MFC(Microsoft Foundation Class Library)。
從邏輯結構和存儲結構來看,基本數據結構的數量是有限的。對於其中的數據結構,用戶可能需要反復的編寫一些類似的的代碼,只是為了適應不同數據的類型變化而在細節上有所出入。如果能夠將這些經典的數據結構,采用
類型參數的形式,設計為
通用的類模板和函數模板的形式,允許用戶
重復利用已有的數據結構構造自己特定類型下的、符合實際需要的數據結構,無疑將簡化程序開發,提高軟件的開發效率,這就是STL編程的基本設計思想。
邏輯層次來看,STL中體現了
泛型化程序設計(generic programming)的思想,它提倡使用現有的模板程序代碼開發應用程序,是一種代碼的重用技術(reusability)。代碼重用可以提高軟件開發人員的勞動生產率和目標系統質量,是軟件工程追求的重要目標。許多程序設計語言通過提供標准庫來實現代碼重用的機制。STL是一個通用組件庫, 它的目標是將常用的數據結構和算法標准化、通用化,這樣用戶可以直接套用而不用重復開發它們,從而提高程序設計的效率。
從
實現層次看,STL是一種
類型參數化(type parameterized)的程序設計方法,是一個基於模板的標准類庫,稱之為
容器類。每種容器都是一種已經建立完成的標准數據結構。在容器中,放入任何類型的數據,很容易建立一個存儲該類型(或類)的數據結構。
STL主要由五個部分組成,分別是容器(container)、迭代器(iterator)、適配器(adaptor)、算法(algorithm)以及函數對象(function object)。
在STL程序設計中,
容器(container)就是
通用的數據結構。容器用來承載不同類型的數據對象,就如同現實生活中,人們使用容器用來裝載各種物品一樣,但C++中的容器還存在一定的“數據加工能力”,它如同一個對數據對象進行加工的模具,可以把不同類型的數據放到這個模具中進行加工處理,形成具有一定共同特性的數據結構。例如將int型、char型或者float型放到隊列容器中,就分別生成int隊列、char型隊列或者float型隊列,它們都是隊列,具有隊列的基本特性,但是具體數據類型是不一樣的。
STL容器主要包括
向量(
vector
)、列表(
list
)、隊列(
deque
)、集合(
set/
multiset
)和映射(
map/multimap
)等。STL用模板實現了這些最常用的數據結構,並以算法的形式提供了對這些容器類的基本操作。
STL中的所有容器都是
類模板,是一個已經建立完成的抽象的數據結構,因此可以使用這些容器來存儲任何類型的數據,甚至是自己定義的類,而無需自己再定義數據結構。例如利用deque容器,就很容易建立一個隊列。
3,STL算法
1,順序容器
容器類名
|
特性
|
何時使用
|
頭文件
|
vector
(向量)
|
在內存中占有一塊連續的空間,存儲一個元素序列。可以看作一個可自動擴充的動態數組,而且提供越界檢查。可用[]運算符直接存取數據。
|
需要快速查找,不在意插入/刪除的速度快慢。能使用數組的地方都能使用向量。
|
<vector>
|
list
(列表)
|
雙向鏈接列表,每個節點包含一個元素。列表中的每個元素均有指針指向前一個元素和下一個元素。
|
需要快速的插入/刪除,不在意查找的速度慢,就可以使用列表。
|
< list >
|
deque
(雙端隊列)
|
在內存中不占有一塊連續的空間,介於向量和列表之間,更接近向量,適用於由兩端存取數據。可用[]運算符直接存取數據。
|
可以提供快速的元素存取。在序列中插入/刪的速度除較慢。一般不需要使用雙端隊列,可以轉而使用vector或list。
|
< deque >
|
容器類名
|
特性
|
何時使用
|
頭文件
|
set
(集合)/
multiset
(多集)
|
set是一個元素集合。集合中的元素按有序的方式存儲。set中沒有重復的元素,但multiset中允許有重復的元素。
|
需要使用元素集合,而且對元素的查找、插入和刪除操作都較為頻繁時,就可以使用set/multiset。
|
<set>
|
map
(映射)/
multimap
(多映射)
|
map是{鍵(key),值}對的組成的集合。集合中的元素按鍵排列。multimap是允許鍵/值對有重復的集合。map和multimap的關系如同set和multiset之間的關系
|
如果希望將鍵/與值相關聯就可以使用map/muitimap。
|
< map >
|
算法(
algorithm
)就是一些常用的數據處理方法,如向容器中插入、刪除容器中的元素、查找容器中的元素、對容器中的元素排序、復制容易中的元素等等,這些數據處理方法是以函數模板的形式實現的實現的。
算法之美就在於它們不僅獨立於底層元素的類型,而且也獨立於所操作的容器,利用這些已經定義的算法和迭代器,程序設計人員可以方便靈活地地存取容器中存儲的各種數據元素。 在STL中,算法的“神奇之處”在於:算法並非容器的一部分,而是工作在迭代器基礎之上,通過迭代器這個“
中間人”存取容器中的元素,算法並沒有和特定的容器進行綁定。 在傳統的軟件開發方法中,算法與數據類型、數據結構緊密耦合,缺乏通用性。而STL 倡導泛型編程風格,即以通用的方式來編寫程序。STL采用C++模板機制實現了算法與數據類型的無關性。實際上,為了支持通用程序設計,STL實現了
算法與容
器(數據結構)的分離。這樣,同一算法適用於不同的容器和數據類型,成為通用性算法,可以最大限度地節省源代碼。因此STL比傳統的函數庫或類庫具有更好的代碼
重用性。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
/*******************************************
* 程序名:p10_9.cpp *
* 功 能:算法(algorithm)示例 *
*******************************************/
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
template<class T>
void print(T &con) //輸出容器中所有元素
{
if(con.empty())
cout<<"Container is empty!"<<endl;
else
{
T::iterator it; //設置迭代器
for(it=con.begin(); it!=con.end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
}
}
|
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
int main()
{
int num;
vector<char> vec_A(8); //定義容器vec_A
cout<<"Fill vec_A with 'A':"<<endl;
fill(vec_A.begin(),vec_A.end(),'A'); //填充數據元素
print(vec_A);
cout<<"Copy element of vector to vec_A:"<<endl;
char array_B[]={'B','B','B','B',};
vector<char> vec_B(array_B,array_B+4); //定義容器vec_A,並初始化
copy(vec_B.begin(),vec_B.end(),vec_A.begin()+2); //復制數據元素
print(vec_A);
cout<<"Remove 'A' from vec_A:"<<endl;
vector<char>
::iterator it;
it=remove(vec_A.begin(),vec_A.end(),'A'); //移除數據元素
vec_A.erase(it,vec_A.end()); //刪除數據元素
print(vec_A);
cout<<"Repalce 'B' with 'C':"<<endl;
replace(vec_A.begin(),vec_A.begin()+2,'B','C'); //替換數據元素
replace(vec_B.begin(),vec_B.end(),'B','X');
print(vec_A);
|
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
cout<<"Inserting:"<<endl;
vec_A.insert(vec_A.begin(),'D'); //
插入數據元素
vec_A.insert(vec_A.end(),'A');
print(vec_A);
cout<<"Sorting:"<<endl;
sort(vec_A.begin(),vec_A.end()); //
排序
print(vec_A);
vector<char>
vec_C(vec_A.size()+vec_B.size());
cout<<"Merge vec_A and vec_B:"<<endl;
merge(vec_A.begin(),vec_A.end(),vec_B.begin(),vec_B.end(),
vec_C.begin()); //
合並
print(vec_C);
num=count(vec_C.begin(),vec_C.end(),'B'); //
統計數據元素
cout<<"Counting the number of 'B' in vec_C:"<<endl;
cout<<num<<endl;
return 0;
}
|
◇ 類模板是能根據不同參數建立不同類型對象的類,類模板中的數據成員、成員
函數的參數、成員函數的返回值可以取參數化類型。
◇ 類模板實例化是在建立對象時,根據傳入的參數類型,將類模板實例化成具
體類,然后再建立對象。
◇ 棧是一種先進后出FILO(First In Last Out)的一種結構,在程序設計中廣
泛使用棧,將棧設計成一個類模板,就可以在棧中存放任意類型的數據。
◇ 動態鏈表的插入與刪除節點的性能優於靜態數組,在程序設計中廣泛使用鏈
表,將鏈表設計成一個類模板,就可以在鏈表節點中存放任意類型的數據。
◇ STL(Standard Template Library)是C++提供的標准模板庫,它可以實現高
效的泛型程序設計。
◇ STL容器包括順序容器和關聯容器,利用容器適配器可以將順序容器轉換為新
的容器。
◇ 在STL中,算法獨立於所操作的容器,利用已經定義的算法和迭代器,用戶可
以方便靈活地地存取容器中存儲的各種數據元素。
◇ 在STL中,函數對象是由模板類產生的對象,函數對象在STL中被廣泛用作算
法中子操作的參數,使算法變得更加通用。