STL是C++标准库的重要组成部分之一,它不仅是一个可复用的组件库,更是一个包含算法与数据结构的软件框架,同时也是C++泛型编程的很好例子。STL中运用了许多C++的高级技术。本文介绍重载操作符。主要参考了《C++ Primer》和《STL源码剖析》。
重载操作符是具有特殊名称的函数:保留了operator后接需定义的操作符符号。这是《C++ Primer》中的定义。在STL中重载操作符主要用在两个地方,一个是迭代器中,另一个是算法中。本文介绍在迭代器中的应用,下篇介绍在算法中的应用。在本系列博文中,多次提到迭代器,不愧是STL的关键所在。迭代器就像是各种容器对象的智能指针,这仅仅是我的理解。指针的各种行为中常见的有解引用操作符(*)、箭头操作符(->)、自增、自减等。对于容器来说,必须重载这些操作符,以适应自身的指针行为。重载这些操作符,迭代器责无旁贷。看一段STL的源码,做了些修改,更清楚一些。
- //结点定义,双向链表
- template <class T>
- struct List_node {
- List_node* next;
- List_node* prev;
- T data;
- };
- //链表的迭代器
- template<class T, class Ref, class Ptr>
- class List_iterator
- {
- public:
- List_node<T> *node;
- void Incr() { node = node->next; }
- void Decr() { node = node->prev; }
- public:
- typedef T value_type;
- typedef Ptr pointer;
- typedef Ref reference;
- typedef size_t size_type;
- typedef ptrdiff_t difference_type;
- typedef bidirectional_iterator_tag iterator_category;
- typedef List_iterator<T, T&, T*> iterator; //迭代器
- typedef List_iterator<T, const T&, const T*> const_iterator;
- typedef List_iterator<T, Ref, Ptr> self;
- List_iterator(List_node<T>* x): node(x) {} //接受链表结点的构造函数,很管用
- List_iterator() {}
- reference operator*() const { return node->data; } //解引用重载
- pointer operator->() const { return &(operator*()); } //箭头重载
- self& operator++() { this->Incr(); return *this; } //前增重载
- self operator++(int) { self tmp = *this; this->Incr(); return tmp; } //后增重载
- self& operator--() { this->Decr(); return *this; } //前减重载
- self operator--(int) { self tmp = *this; this->Decr(); return tmp; } //后减重载
- bool operator==(const List_iterator& x) const { return node == x.node; } //相等重载
- bool operator!=(const List_iterator& x) const { return node != x.node; } //不相等重载
- };
上面这段代码展现了这些操作符是如何被重载。其实这是个双向链表的迭代器定义,有自增和自减。再进一步,那么链表如何使用上述定义的迭代器呢?下面给出链表的定义,只取STL链表的部分功能,同时给出了测试用例。已在VS2008下测试通过。
- #include <iostream>
- using namespace std;
- //结点定义,双向链表,把上面的代码拷贝下来即可
- //链表的迭代器,把上面的代码拷贝下来即可
- //资源分配器
- class MyAlloc
- {
- };
- //链表定义
- template <class T, class Alloc = MyAlloc >
- class List {
- public:
- typedef List_node<T> list_node; //结点类型
- typedef list_node* list_type; //结点指针
- typedef T value_type;
- typedef value_type* pointer;
- typedef const value_type* const_pointer;
- typedef value_type& reference;
- typedef const value_type& const_reference;
- typedef size_t size_type;
- typedef ptrdiff_t difference_type;
- typedef List_iterator<T, T&, T*> iterator; //迭代器
- typedef List_iterator<T, const T&, const T*> const_iterator;
- public:
- List() { node = get_node(); node->next = node; node->prev = node; } //构造哨兵结点
- ~List() { clear(); }
- //返回类型要求是iterator,而实际返回的是结点指针,为什么可以呢?关键在于List_iterator有一个接受结点指针的构造函数
- iterator begin() { return node->next; }
- const_iterator begin() const { return node->next; }
- iterator end() { return node; }
- const_iterator end() const { return node; }
- bool empty() const { return node->next == node; }
- reference front() { return *begin(); }
- const_reference front() const { return *begin(); }
- reference back() { return *(--end()); }
- const_reference back() const { return *(--end()); }
- void push_front(const T& x) { insert(begin(), x); }
- void push_back(const T& x) { insert(end(), x); }
- void pop_front() { erase(begin()); }
- void pop_back() { iterator tmp = end(); erase(--tmp); }
- //插入结点
- void insert(iterator pos, const T &x) {
- list_type tmp = get_node();
- tmp->data = x;
- tmp->next = pos.node;
- tmp->prev = pos.node->prev;
- (pos.node->prev)->next = tmp;
- pos.node->prev = tmp;
- }
- //删除结点
- iterator erase(iterator pos) {
- list_type next_node = pos.node->next;
- list_type prev_node = pos.node->prev;
- prev_node->next = next_node;
- next_node->prev = prev_node;
- put_node(pos.node);
- return next_node;
- }
- //清除所有结点
- void clear() {
- list_type cur = node->next;
- while(cur != node)
- {
- list_type tmp = cur;
- cur = cur->next;
- put_node(tmp);
- }
- node->next = node;
- node->prev = node;
- }
- private:
- list_type node;
- list_type get_node() { return new list_node; } //分配空间
- void put_node(list_type p) { delete p; p = NULL; } //释放空间
- };
- //测试用例
- int main()
- {
- List<int> l;
- l.push_back(1);
- l.push_back(2);
- cout<<l.front()<<' '<<l.back()<<endl; //1 2
- l.push_front(3);
- l.push_front(4);
- cout<<l.front()<<' '<<l.back()<<endl; //4 2
- l.pop_back();
- l.pop_front();
- cout<<l.front()<<' '<<l.back()<<endl; //3 1
- cout<<l.empty()<<endl; //0
- l.clear();
- cout<<l.empty()<<endl; //1
- return 0;
- }
上面这两段程序已经给出了链表的部分功能,同时看到了迭代器的运用以及重载操作符的实现。搞清楚了以上代码,再去看STL的源代码,可能会轻松一点吧,大同小异,核心的结构基本上都是这样的