跟據侯捷的《STL源碼剖析》一書中提到的《Design Patterns》一書中關於iterator模式定義:提供一種方法,使之能夠依序尋訪某個聚合物(容器)所含的各個元素,而又無需暴露該聚合物的內部表達方式。
當然,STL的中心思想在於:將數據容器和算法分開,彼此單獨設計,最後再以一帖膠着劑將他們撮合在一起。
迭代器可以看作是一種smart pointer,故要進行內容提領和成員訪問,關鍵的工作就是對operator*和operator->進行重載
//忽略模板類定義 T &operator*()const {return *pointee;} //其中T作爲模板參數 T* operator->() const{return pointee;} //pointee作爲已定義成員
當然iterator的設計中有一條關鍵的地方就是封裝和隱藏,在此不提。
爲了引出STL設計的關鍵部分——Traits,需提到一個“相應型別”,也就是迭代其所指之物的類型。
在c++中只有sizeof()和RTTI中的typeid(),前者只能判斷出類型大小,無法進行類型確定,後者由於得到的只是一種別名(vs環境下爲全程,MinGW下只是開頭字母例如“int”中的‘i’。)況且後者屬於運行期判斷,不僅需要virutal而且判斷期靠後因此不能拿來使用。
我們在這裏需要的並不是輸出一個類型的名稱,而是在調用過程中間接使用,將其隱藏起來。因此使用模板的類型推斷是個不錯的做法。
迭代器相應型別最常用的有五種,分別是value_type,difference_type,reference,pointer,iterator_category。
這裏我們爲了下面的Iterator_Traits技術需要提到一下模板偏特化問題。
例如:
template<typename T> struct test { typedef T value_type; T *pointer; }; template<typename T> //偏特化 struct test<T*> { typedef T value_type; }
偏特化的定義:針對任何template參數更進一步的條件限制所設計出來的一個特化版本。
我們需要考慮的偏特化情形有如下情況:
1.原始指針
2 .const T *
之所以進行以下兩種特化,主要願意是1.原始指針無法進行內置型別的定義,也就是說無法進行typedef操作,故對以後的過濾會造成很大的麻煩,而且原始指針不能夠被忽略。2.對於const T*來說,不能夠被輕易修改,而且如果不另外考慮,也會造成不必要的麻煩。
可對照一下代碼
//原模板 template<typename T> struct test { typedef T value_type; };
//原始指針特化 template<typename T> struct test<T*> { typedef T value_type; };
//const pointer template<typename T> struct test<const T*> { typedef T value_type; };
這樣,我們不管是調用哪個,都會有一個value_type,而這個value_type到底是何方神聖,已經被我們隱藏起來了。
我們可以依照上述例子描述difference_type,pointer,reference。但是difference_type可以typedef庫中的ptrdiff_t,來實現。
至此,我們只剩下了iterator_category這一個類型了。
iterator_category作爲一個指針移動的特性和實行操作,我們有如下五類:
Input Iterator Output Interator Forward Iterator Bidirectional Iterator Random Access Iterator
其中 input 和output這兩種屬於訪問權限修飾,其他的三種依次深入,我們可以從下面代碼中看出
struct input_iterator{};
//只讀 struct output_iterator{}; //只寫 struct forward_iterator: public input_iterator{}; //寫入型,單項型操作 struct bidirectional_iterator: public forward_iterator{};
//可雙向移動 struct random_access_iterator: public bidirectional_iterator{};
//可進行跳躍訪問,涵蓋所有指針的運算能力 |
c++中的多態性中有一個重載的概念,也就是說有如下例子
#include<iostream><br>using
namespace std;<br>class base { //empty }; class deriver: public base { //empty }; void test(base
&) { //empty; }<br> int main()<br>{<br>base
b;<br>deriver d;<br>test(b); //ok
<br>test(d); //ok<br>} |
這樣,我們就可以寫更少的函數來實現我們需要的所有方法
好,爲了使上述居多的描述更加清晰可見,思路更加清晰,上一大段代碼進行分析
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
#include<iostream> using namespace std; struct input_iterator{}; struct output_iterator{}; struct forward_iterator: public input_iterator{}; struct bidirectional_iterator:forward_iterator{}; struct random_access_iterator:bidirectional_iterator{}; template < typename Category, typename T, typename Distance= ptrdiff_t , typename Pointer=T*, typename Reference=T&> struct iterator { typedef Category
iterator_category; typedef T
value_type; typedef Pointer
pointer; typedef Reference
reference; typedef Distance
difference_type; }; template < typename Iterator> struct Iterator_traitss { typedef typename Iterator::iterator_catergory
iterator_category; typedef typename Iterator::value_type
value_type; typedef typename Iterator::pointer
pointer; typedef typename Iterator::reference
reference; typedef typename Iterator::difference_type
difference_type; }; template < typename T> struct iterator_traitss<T*> { typedef random_access_iterator
iterator_category; typedef T
value_type; typedef ptrdiff_t difference_type; typedef T*
pointer; typedef T&
reference; }; template < typename T> struct iterator_traitss< const T*> { typedef random_access_iterator
iterator_category; typedef T
value_type; typedef ptrdiff_t difference_type; typedef const T*
pointer; typedef const T&
reference; }; template < typename Iterator> inline typename iterator_traits<Iterator>::iterator_category iterator_category( const Iterator&) { typedef typename iterator_traitss<Iterator>::iterator_category
category; return category(); } int main() { } |
通過上述代碼我們可以清晰看到,有一個iterator類模板,我們在其中的模板參數除了第一個參數外,其他的都有默認值,這個和我們現在使用的vector<T>等其中的Iterator是一致的 。
有了iterator模板後,我們需要一個強有勁的過濾器,那就是iterator_traits,這個可以將模板參數不管是什麼樣的,統統封裝成統一的typedef,例如 value_type的形成。
這樣我們就可以很方便的進行下面的操作。請注意在iterator_traits中T*的特化還有const T*的特化那裏,iterator_category的原名是random_access_iterator.
總結:
我們可以通過typedef機制,隱藏,集中一類特性。
我們可以通過模板參數推導機制,針對同一別名的不同類型進行不同操作。爲了效率因素,進行編譯期多態而非運行期多態。