STL运用的C++技术(5)——重载操作符

转载 2016年05月31日 11:00:05

 STL是C++标准库的重要组成部分之一,它不仅是一个可复用的组件库,更是一个包含算法与数据结构的软件框架,同时也是C++泛型编程的很好例子。STL中运用了许多C++的高级技术。本文介绍重载操作符。主要参考了《C++ Primer》和《STL源码剖析》。

       重载操作符是具有特殊名称的函数:保留了operator后接需定义的操作符符号。这是《C++ Primer》中的定义。在STL中重载操作符主要用在两个地方,一个是迭代器中,另一个是算法中。本文介绍在迭代器中的应用,下篇介绍在算法中的应用。在本系列博文中,多次提到迭代器,不愧是STL的关键所在。迭代器就像是各种容器对象的智能指针,这仅仅是我的理解。指针的各种行为中常见的有解引用操作符(*)、箭头操作符(->)、自增、自减等。对于容器来说,必须重载这些操作符,以适应自身的指针行为。重载这些操作符,迭代器责无旁贷。看一段STL的源码,做了些修改,更清楚一些。

  1. //结点定义,双向链表  
  2. template <class T>  
  3. struct List_node {  
  4.     List_node* next;  
  5.     List_node* prev;  
  6.     T data;  
  7. };  
  8. //链表的迭代器  
  9. template<class T, class Ref, class Ptr>  
  10. class List_iterator  
  11. {  
  12. public:  
  13.     List_node<T> *node;  
  14.     void Incr() { node = node->next; }  
  15.     void Decr() { node = node->prev; }  
  16. public:  
  17.     typedef T value_type;  
  18.     typedef Ptr pointer;  
  19.     typedef Ref reference;  
  20.     typedef size_t                     size_type;  
  21.     typedef ptrdiff_t                  difference_type;  
  22.     typedef bidirectional_iterator_tag iterator_category;  
  23.   
  24.     typedef List_iterator<T, T&, T*>             iterator;        //迭代器  
  25.     typedef List_iterator<T, const T&, const T*> const_iterator;  
  26.     typedef List_iterator<T, Ref, Ptr>           self;  
  27.       
  28.     List_iterator(List_node<T>* x): node(x) {}     //接受链表结点的构造函数,很管用  
  29.     List_iterator() {}  
  30.     reference operator*() const { return node->data; }                        //解引用重载  
  31.     pointer operator->() const { return &(operator*()); }                     //箭头重载  
  32.     self& operator++() { this->Incr(); return *this; }                        //前增重载  
  33.     self operator++(int) { self tmp = *thisthis->Incr(); return tmp; }      //后增重载  
  34.     self& operator--() { this->Decr(); return *this; }                        //前减重载  
  35.     self operator--(int) { self tmp = *thisthis->Decr(); return tmp; }      //后减重载  
  36.     bool operator==(const List_iterator& x) const { return node == x.node; }  //相等重载  
  37.     bool operator!=(const List_iterator& x) const { return node != x.node; }  //不相等重载  
  38. };  

      上面这段代码展现了这些操作符是如何被重载。其实这是个双向链表的迭代器定义,有自增和自减。再进一步,那么链表如何使用上述定义的迭代器呢?下面给出链表的定义,只取STL链表的部分功能,同时给出了测试用例。已在VS2008下测试通过。

  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. //结点定义,双向链表,把上面的代码拷贝下来即可  
  5. //链表的迭代器,把上面的代码拷贝下来即可  
  6.   
  7. //资源分配器  
  8. class MyAlloc  
  9. {  
  10. };  
  11. //链表定义  
  12. template <class T, class Alloc = MyAlloc >  
  13. class List {  
  14. public:        
  15.     typedef List_node<T> list_node; //结点类型  
  16.     typedef list_node* list_type;   //结点指针  
  17.   
  18.     typedef T value_type;  
  19.     typedef value_type* pointer;  
  20.     typedef const value_type* const_pointer;  
  21.     typedef value_type& reference;  
  22.     typedef const value_type& const_reference;  
  23.     typedef size_t size_type;  
  24.     typedef ptrdiff_t difference_type;  
  25.   
  26.     typedef List_iterator<T, T&, T*>             iterator; //迭代器  
  27.     typedef List_iterator<T, const T&, const T*> const_iterator;  
  28. public:  
  29.     List() { node = get_node(); node->next = node; node->prev = node; } //构造哨兵结点  
  30.     ~List() { clear(); }    
  31.     //返回类型要求是iterator,而实际返回的是结点指针,为什么可以呢?关键在于List_iterator有一个接受结点指针的构造函数  
  32.     iterator begin()             { return node->next; }   
  33.     const_iterator begin() const { return node->next; }  
  34.     iterator end()               { return node; }  
  35.     const_iterator end() const   { return node; }  
  36.     bool empty() const { return node->next == node; }  
  37.     reference front() { return *begin(); }  
  38.     const_reference front() const { return *begin(); }  
  39.     reference back() { return *(--end()); }  
  40.     const_reference back() const { return *(--end()); }  
  41.     void push_front(const T& x) { insert(begin(), x); }  
  42.     void push_back(const T& x) { insert(end(), x); }  
  43.     void pop_front() { erase(begin()); }  
  44.     void pop_back() {  iterator tmp = end(); erase(--tmp); }  
  45.     //插入结点  
  46.     void insert(iterator pos, const T &x) {              
  47.         list_type tmp = get_node();  
  48.         tmp->data = x;  
  49.         tmp->next = pos.node;   
  50.         tmp->prev = pos.node->prev;  
  51.         (pos.node->prev)->next = tmp;  
  52.         pos.node->prev = tmp;  
  53.     }  
  54.     //删除结点  
  55.     iterator erase(iterator pos) {   
  56.         list_type next_node = pos.node->next;  
  57.         list_type prev_node = pos.node->prev;  
  58.         prev_node->next = next_node;  
  59.         next_node->prev = prev_node;  
  60.         put_node(pos.node);  
  61.         return next_node;  
  62.     }  
  63.     //清除所有结点  
  64.     void clear() {  
  65.         list_type cur = node->next;  
  66.         while(cur != node)  
  67.         {  
  68.             list_type tmp = cur;  
  69.             cur = cur->next;  
  70.             put_node(tmp);  
  71.         }  
  72.         node->next = node;  
  73.         node->prev = node;  
  74.     }  
  75. private:  
  76.     list_type node;  
  77.     list_type get_node() { return new list_node; }      //分配空间  
  78.     void put_node(list_type p) { delete p; p = NULL; }  //释放空间  
  79. };  
  80. //测试用例  
  81. int main()  
  82. {  
  83.     List<int> l;  
  84.     l.push_back(1);  
  85.     l.push_back(2);  
  86.     cout<<l.front()<<' '<<l.back()<<endl; //1 2  
  87.     l.push_front(3);  
  88.     l.push_front(4);  
  89.     cout<<l.front()<<' '<<l.back()<<endl; //4 2  
  90.     l.pop_back();  
  91.     l.pop_front();  
  92.     cout<<l.front()<<' '<<l.back()<<endl; //3 1    
  93.     cout<<l.empty()<<endl;  //0  
  94.     l.clear();  
  95.     cout<<l.empty()<<endl;  //1  
  96.     return 0;  
  97. }  

       上面这两段程序已经给出了链表的部分功能,同时看到了迭代器的运用以及重载操作符的实现。搞清楚了以上代码,再去看STL的源代码,可能会轻松一点吧,大同小异,核心的结构基本上都是这样的。

C++ STL 基础及应用(2) 模板与操作符重载

模板是 C++ 语言中重要的概念。它提供了一种通用的方法来开发重用的代码,即以创建参数化的 C++ 类型。 本章将阐述一些具体的 STL 模板思想,并简单介绍操作符重载与模板的联系。 文中将给出一个简...
  • Raito__
  • Raito__
  • 2016年05月22日 17:13
  • 2666

C++ vector 自定义类,重载==操作符,使用STL的find查找

#include #include #include #include using namespace std; class onec { private: int i; ...
  • syrchina
  • syrchina
  • 2016年02月18日 14:09
  • 2870

map复合key值,如何重载操作符?

1 2 3 4 5 6 7 8 9 10 11 12 struct __key { int nParam...
  • qq_31209383
  • qq_31209383
  • 2017年03月02日 14:56
  • 356

STL运用的C++技术(5)——重载操作符

STL是C++标准库的重要组成部分之一,它不仅是一个可复用的组件库,更是一个包含算法与数据结构的软件框架,同时也是C++泛型编程的很好例子。STL中运用了许多C++的高级技术。本文介绍重载操作符。主要...
  • lvfengchang1220
  • lvfengchang1220
  • 2015年05月16日 15:55
  • 221

C++ 重载操作符 operator

参数个数的限定     非成员函数:   单目运算符:参数表中只有一个参数;   双目运算符:参数表中只有两个参数       成员函数:   单目运算符:参数表中没有参数; ...
  • fenhong91
  • fenhong91
  • 2017年02月07日 09:55
  • 1025

C++结构体作为map的key的时候需要重载<运算符

typedef struct DICOMRowsAndVolumn{ CString strRows; CString strColumn; bool operator { if(this...
  • qq0824
  • qq0824
  • 2016年08月31日 17:11
  • 234

C++重载[]数组操作符

#include #include using namespace std; class CharPair{ public: CharPair(){ } CharPair(char f...
  • w397090770
  • w397090770
  • 2012年03月18日 14:46
  • 6363

C++运算符重载(4) - 不能被重载的操作符

C++,中,下面的操作符是不能被重载的: . (成员访问或点操作符) ?: (三元操作符或条件操作符) :: (范围操作符) .* (指向成员的指针操作符) sizeof (取对象大小操作符) typ...
  • shltsh
  • shltsh
  • 2015年05月26日 09:39
  • 2174

C++面向对象操作符重载:调用操作符和函数对象

1、定义了调用操作符的类,其对象常称为函数对象,即它们是行为类似函数的对象。      可以为类类型的对象重载函数调用操作符。一般为表示操作的类重载调用操作符。函数调用操作符必须声明为成员函数。一个...
  • QQrenzai
  • QQrenzai
  • 2015年11月11日 08:58
  • 1099

对于c++中流操作符重载的理解

对于IO成员函数的重载不应该是一个成员函数的方式,并且应该声明为友元 一、如果为成员函数,都会有一个某人的参数,也就是this指针,为左操作数,下面考虑将其声明为成员函数的方式 对于cout 对于...
  • lightblueme
  • lightblueme
  • 2015年03月28日 13:01
  • 752
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:STL运用的C++技术(5)——重载操作符
举报原因:
原因补充:

(最多只允许输入30个字)