STL是C++標準庫的重要組成部分之一,它不僅是一個可複用的組件庫,更是一個包含演算法與資料結構的軟體架構,同時也是C++泛型程式設計的很好例子。STL中運用了許多C++的進階技術。本文介紹重載操作符。主要參考了《C++
Primer》和《STL源碼剖析》。
重載操作符是具有特殊名稱的函數:保留了operator後接需定義的操作符符號。這是《C++ Primer》中的定義。在STL中重載操作符主要用在兩個地方,一個是迭代器中,另一個是演算法中。本文介紹在迭代器中的應用,下篇介紹在演算法中的應用。在本系列博文中,多次提到迭代器,不愧是STL的關鍵所在。迭代器就像是各種容器物件的智能指標,這僅僅是我的理解。指標的各種行為中常見的有解引用操作符(*)、箭頭操作符(->)、自增、自減等。對於容器來說,必須重載這些操作符,以適應自身的指標行為。重載這些操作符,迭代器責無旁貸。看一段STL的源碼,做了些修改,更清楚一些。
//結點定義,雙向鏈表<br />template <class T><br />struct List_node {<br />List_node* next;<br />List_node* prev;<br />T data;<br />};<br />//鏈表的迭代器<br />template<class T, class Ref, class Ptr><br />class List_iterator<br />{<br />public:<br />List_node<T> *node;<br />void Incr() { node = node->next; }<br />void Decr() { node = node->prev; }<br />public:<br />typedef T value_type;<br />typedef Ptr pointer;<br />typedef Ref reference;<br />typedef size_t size_type;<br />typedef ptrdiff_t difference_type;<br />typedef bidirectional_iterator_tag iterator_category;</p><p>typedef List_iterator<T, T&, T*> iterator; //迭代器<br />typedef List_iterator<T, const T&, const T*> const_iterator;<br />typedef List_iterator<T, Ref, Ptr> self;</p><p>List_iterator(List_node<T>* x): node(x) {} //接受鏈表結點的建構函式,很管用<br />List_iterator() {}<br />reference operator*() const { return node->data; } //解引用重載<br />pointer operator->() const { return &(operator*()); } //箭頭重載<br />self& operator++() { this->Incr(); return *this; } //前增重載<br /> self operator++(int) { self tmp = *this; this->Incr(); return tmp; } //後增重載<br />self& operator--() { this->Decr(); return *this; } //前減重載<br />self operator--(int) { self tmp = *this; this->Decr(); return tmp; } //後減重載<br />bool operator==(const List_iterator& x) const { return node == x.node; } //相等重載<br />bool operator!=(const List_iterator& x) const { return node != x.node; } //不相等重載<br />};
上面這段代碼展現了這些操作符是如何被重載。其實這是個雙向鏈表的迭代器定義,有自增和自減。再進一步,那麼鏈表如何使用上述定義的迭代器呢?下面給出鏈表的定義,只取STL鏈表的部分功能,同時給出了測試案例。已在VS2008下測試通過。
#include <iostream><br />using namespace std;</p><p>//結點定義,雙向鏈表,把上面的代碼拷貝下來即可<br />//鏈表的迭代器,把上面的代碼拷貝下來即可</p><p>//資源分派器<br />class MyAlloc<br />{<br />};<br />//鏈表定義<br />template <class T, class Alloc = MyAlloc ><br />class List {<br />public:<br />typedef List_node<T> list_node; //結點類型<br />typedef list_node* list_type; //結點指標</p><p> typedef T value_type;<br /> typedef value_type* pointer;<br /> typedef const value_type* const_pointer;<br /> typedef value_type& reference;<br /> typedef const value_type& const_reference;<br /> typedef size_t size_type;<br /> typedef ptrdiff_t difference_type;</p><p>typedef List_iterator<T, T&, T*> iterator; //迭代器<br />typedef List_iterator<T, const T&, const T*> const_iterator;<br />public:<br />List() { node = get_node(); node->next = node; node->prev = node; } //構造哨兵結點<br />~List() { clear(); }<br />//傳回型別要求是iterator,而實際返回的是結點指標,為什麼可以呢?關鍵在於List_iterator有一個接受結點指標的建構函式<br />iterator begin() { return node->next; }<br /> const_iterator begin() const { return node->next; }<br /> iterator end() { return node; }<br /> const_iterator end() const { return node; }<br />bool empty() const { return node->next == node; }<br />reference front() { return *begin(); }<br />const_reference front() const { return *begin(); }<br />reference back() { return *(--end()); }<br />const_reference back() const { return *(--end()); }<br />void push_front(const T& x) { insert(begin(), x); }<br />void push_back(const T& x) { insert(end(), x); }<br />void pop_front() { erase(begin()); }<br />void pop_back() { iterator tmp = end(); erase(--tmp); }<br />//插入結點<br />void insert(iterator pos, const T &x) {<br />list_type tmp = get_node();<br />tmp->data = x;<br />tmp->next = pos.node;<br />tmp->prev = pos.node->prev;<br />(pos.node->prev)->next = tmp;<br />pos.node->prev = tmp;<br />}<br />//刪除結點<br />iterator erase(iterator pos) {<br />list_type next_node = pos.node->next;<br />list_type prev_node = pos.node->prev;<br />prev_node->next = next_node;<br />next_node->prev = prev_node;<br />put_node(pos.node);<br />return next_node;<br />}<br />//清除所有結點<br />void clear() {<br />list_type cur = node->next;<br />while(cur != node)<br />{<br />list_type tmp = cur;<br />cur = cur->next;<br />put_node(tmp);<br />}<br />node->next = node;<br />node->prev = node;<br />}<br />private:<br />list_type node;<br />list_type get_node() { return new list_node; } //分配空間<br />void put_node(list_type p) { delete p; p = NULL; } //釋放空間<br />};<br />//測試案例<br />int main()<br />{<br />List<int> l;<br />l.push_back(1);<br />l.push_back(2);<br />cout<<l.front()<<' '<<l.back()<<endl; //1 2<br />l.push_front(3);<br />l.push_front(4);<br />cout<<l.front()<<' '<<l.back()<<endl; //4 2<br />l.pop_back();<br />l.pop_front();<br />cout<<l.front()<<' '<<l.back()<<endl; //3 1<br />cout<<l.empty()<<endl; //0<br />l.clear();<br />cout<<l.empty()<<endl; //1<br />return 0;<br />}
上面這兩段程式已經給出了鏈表的部分功能,同時看到了迭代器的運用以及重載操作符的實現。搞清楚了以上代碼,再去看STL的原始碼,可能會輕鬆一點吧,大同小異,核心的結構基本上都是這樣的。
轉載出處
http://blog.csdn.net/wuzhekai1985