跟據侯捷的《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>
using namespace std;
class base { //empty }; class deriver:public base { //empty }; void test(base &) { //empty; }
int main()
{
base b;
deriver d;
test(b); //ok
test(d); //ok
}
這樣,我們就可以寫更少的函數來實現我們需要的所有方法
好,為了使上述居多的描述更加清晰可見,思路更加清晰,上一大段代碼進行分析
#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機制,隱藏,集中一類特性。
我們可以通過模板參數推導機制,針對同一別名的不同類型進行不同操作。為了效率因素,進行編譯期多態而非運行期多態。
