zoukankan      html  css  js  c++  java
  • STL源码剖析(适配器)

    STL中由三类适配器,它们分别是:

    1.容器适配器(stack、queue)

    2.迭代器适配器(insert_iterator、reverse_iterator、iostream_iterator)

    3.函数适配器(bind1st等等)

    容器适配器

    关于容器适配器我们已经在前面的http://www.cnblogs.com/runnyu/p/6003821.html讲过了。

    迭代器适配器

    1.insert iterator

    当我们这样使用copy算法的时候:

    1 vector<int> ins = { 1, 3, 5, 7};
    2 vector<int> coll;  // coll为空
    3 copy(ins.begin(), ins.end(), coll.begin());
    View Code

    毫无疑问会出现错误,因为copy算法中调用的是iterator的operator*跟operator=,用的是赋值操作,而要进行赋值的iterator并不合法。

    insert iterator可以解决这个问题,其实它的实现很简单。

    下面是back_inserter的用法跟实现,它的实现主要是重载了operator*跟operator=方法,然后提供了一个接口函数。

     1 // 以容器为参数  将元素copy到coll的末尾
     2 copy(ins.begin(), ins.end(), back_inserter(coll));
     3 
     4 template <class Container>
     5 class back_insert_iterator {
     6 protected:
     7   Container* container;
     8 public:
     9     typedef output_iterator_tag iterator_category;  // output迭代器
    10     typedef void                value_type;
    11     typedef void                difference_type;
    12     typedef void                pointer;
    13     typedef void                reference;
    14 
    15     explicit back_insert_iterator(Container& x) : container(&x) {}
    16 
    17     // 重载operator= 改用push_back
    18     back_insert_iterator<Container>&
    19     operator=(const typename Container::value_type& value) { 
    20         container->push_back(value);
    21         return *this;
    22     }
    23     back_insert_iterator<Container>& operator*() { return *this; }
    24     back_insert_iterator<Container>& operator++() { return *this; }
    25     back_insert_iterator<Container>& operator++(int) { return *this; }
    26 };
    27 
    28 
    29 // 对外提供了该接口
    30 template <class Container>
    31 inline back_insert_iterator<Container> back_inserter(Container& x) {
    32     return back_insert_iterator<Container>(x);
    33 }
    View Code

    front_inserter的用法跟实现类似,只是用push_front代替push_back而已。

    inserter的用法跟实现只是比前面两个多了一个指定位置的迭代器而已。

     1 template <class Container>
     2 class insert_iterator {
     3 protected:
     4     Container* container;
     5     // 其成员多了一个迭代器
     6     typename Container::iterator iter;
     7 public:
     8     typedef output_iterator_tag iterator_category;
     9     typedef void                value_type;
    10     typedef void                difference_type;
    11     typedef void                pointer;
    12     typedef void                reference;
    13 
    14     insert_iterator(Container& x, typename Container::iterator i) 
    15       : container(&x), iter(i) {}
    16 
    17     // 改用insert方法
    18     insert_iterator<Container>&
    19     operator=(const typename Container::value_type& value) { 
    20         iter = container->insert(iter, value);
    21         ++iter;
    22         return *this;
    23     }
    24     insert_iterator<Container>& operator*() { return *this; }
    25     insert_iterator<Container>& operator++() { return *this; }
    26     insert_iterator<Container>& operator++(int) { return *this; }
    27 };
    28 
    29 // 对外提供的接口
    30 template <class Container, class Iterator>
    31 inline insert_iterator<Container> inserter(Container& x, Iterator i) {
    32     typedef typename Container::iterator iter;
    33     return insert_iterator<Container>(x, iter(i));
    34 }
    View Code

    2.reserve iterator

    容器的实现中的rbegin()跟rend()就是使用的是reserve_iterator。

    为了能够兼容算法,进行反向遍历,reserver iterator的operator++跟operator--应该跟普通迭代器的行为相反。

     1 class vector
     2 {
     3     //...
     4     // 使用的就是reverse_iterator
     5     reverse_iterator rbegin() { return reverse_iterator(end()); }
     6     reverse_iterator rend() { return reverse_iterator(begin()); }
     7     // ...
     8 };
     9 
    10 // reserve_iterator的实现
    11 template <class Iterator>
    12 class reverse_iterator 
    13 {
    14 protected:
    15     Iterator current;
    16 public:
    17     // ...
    18     typedef Iterator iterator_type;
    19     typedef reverse_iterator<Iterator> self;
    20     
    21     // 构造函数    
    22     explicit reverse_iterator(iterator_type x) : current(x) {}
    23 
    24     // 将迭代器前移一步 才能保持跟正向迭代器的一切惯常行为
    25     // 如rbegin()就是end() - 1  指向反向的第一个可用元素
    26     reference operator*() const {
    27         Iterator tmp = current;
    28         return *--tmp;
    29     }
    30     
    31     // operator++跟operator--跟普通迭代器行为相反 
    32     // 使得reverse_iterator能进行反向遍历
    33     self& operator++() {
    34         --current;
    35         return *this;
    36     }
    37     self& operator--() {
    38         ++current;
    39         return *this;
    40     }
    41     // ... 还重载了operator+=、operator-=等等
    42 };
    View Code

    3.iostream iterator

    iostream_iterator内部都维护一个流对象。

    先看看istream_iterator的用法:

     1 // 先看看istream_iterator的用法
     2 vector<int> coll;
     3 // 调用的是无参构造函数(end_marker = false)
     4 istream_iterator<int> end;
     5 copy(istream_iterator<int>(cin), end, back_inserter(coll));
     6 
     7 // 然后看看它调用的copy版本
     8 // 可见istream_iterator需要重载operator==、operator*、operator++等等操作符
     9 for ( ; first != last; ++result, ++first)
    10     *result = *first;
    11 return result;
    12 
    13 // 结束条件为first != last  
    14 // 因此istream_iterator需要重载operator== 这是一个友元函数
    15 // 根据end_marker(为false表示读到eof或者读到不符合要求的数据)进行判断
    16 // 因此调用默认构造函数的istream_iterator可以当做end()
    17 template <class T,end_marker class Distance>
    18 inline bool operator==(const istream_iterator<T, Distance>& x,
    19                        const istream_iterator<T, Distance>& y) {
    20   return x.stream == y.stream && x.end_marker == y.end_marker ||
    21          x.end_marker == false && y.end_marker == false;
    22 }
    View Code

    现在再看istream_iterator的实现就比较简单了:

     1 template <class T, class Distance = ptrdiff_t> 
     2 class istream_iterator {
     3 protected:
     4     istream* stream;
     5     T value;
     6     bool end_marker;
     7 
     8     // 读到eof或者不符合要求的数据时将end_marker设置为false
     9     void read() {
    10         end_marker = (*stream) ? true : false;
    11         // 从istream中读取一个值并复制给value
    12         if (end_marker) *stream >> value;
    13         end_marker = (*stream) ? true : false;
    14     }
    15 public:
    16     typedef input_iterator_tag iterator_category;
    17     typedef T                  value_type;
    18     typedef Distance           difference_type;
    19     typedef const T*           pointer;
    20     typedef const T&           reference;
    21 
    22     // 无参构造函数  这个是结束的关键
    23     istream_iterator() : stream(&cin), end_marker(false) {}
    24 
    25     // 调用read() 程序将等待输入
    26     istream_iterator(istream& s) : stream(&s) { read(); }
    27         
    28         // 取出当前读到的元素
    29     reference operator*() const { return value; }
    30 
    31     // 实际上调用的是read() 每次调用operator++都等待用户输入
    32     istream_iterator<T, Distance>& operator++() { 
    33         read(); 
    34         return *this;
    35     }
    36 };
    View Code

    而作为output iterator的ostream_iterator则是维护一个ostream member,重载其operator=方法

    直接看它的用法跟实现:

     1 list<int> coll = { 1, 3, 5, 7, 9 };
     2 // ostream_iterator接受一个ostream对象跟一个分隔符
     3 copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, " "));
     4 
     5 // ostream_iterator的实现
     6 template <class T>
     7 class ostream_iterator {
     8 protected:
     9     ostream* stream;
    10     // 分隔符
    11     const char* string;
    12 public:
    13     typedef output_iterator_tag iterator_category;
    14     typedef void                value_type;
    15     typedef void                difference_type;
    16     typedef void                pointer;
    17     typedef void                reference;
    18 
    19     ostream_iterator(ostream& s) : stream(&s), string(0) {}
    20     ostream_iterator(ostream& s, const char* c) : stream(&s), string(c)  {}
    21 
    22     // 重载operator= 首先输出value  然后输出分隔符
    23     ostream_iterator<T>& operator=(const T& value) { 
    24         *stream << value;
    25         if (string) *stream << string;
    26         return *this;
    27     }
    28     // 返回该对象(结合copy的*result=理解)
    29     ostream_iterator<T>& operator*() { return *this; }
    30     ostream_iterator<T>& operator++() { return *this; } 
    31     ostream_iterator<T>& operator++(int) { return *this; } 
    32 };
    33         
    View Code

    函数适配器

    前面已经说过函数适配器bind2nd的实现:http://www.cnblogs.com/runnyu/p/6010101.html。

    其实函数适配器都是在构造的时候将仿函数跟需要的参数设置为其成员,然后重载operator()对其成员进行修饰。

    还有值得一看的是ptr_fun跟mem_fun的实现,它们可以将普通/成员函数变成一个仿函数,

    其实实现就是该function object拥有一个函数指针,并重载operator()方法而已。

    ptr_fun实现比较简单:

     1 template <class Arg, class Result>
     2 class pointer_to_unary_function : public unary_function<Arg, Result> {
     3 protected:
     4     // 拥有其函数指针 该函数参数数量为1
     5     Result (*ptr)(Arg);
     6 public:
     7     pointer_to_unary_function() {}
     8     explicit pointer_to_unary_function(Result (*x)(Arg)) : ptr(x) {}
     9     // 重载operator()  使得该对象为function object
    10     Result operator()(Arg x) const { return ptr(x); }
    11 };
    12 
    13 // 对外提供的接口
    14 template <class Arg, class Result>
    15 inline pointer_to_unary_function<Arg, Result> ptr_fun(Result (*x)(Arg)) {
    16     return pointer_to_unary_function<Arg, Result>(x);
    17 }
    View Code

    mem_fun有多个版本,下面给出一种(无参数、通过pointer调用、non-const成员函数)的实现:

     1 template <class T>
     2 class mem_fun_t<void, T> : public unary_function<T*, void> {
     3 public:
     4     explicit mem_fun_t(void (T::*pf)()) : f(pf) {} 
     5     // 重载operator() 使其变成一个function object
     6     // 成员函数默认带一个this指针
     7     void operator()(T* p) const { (p->*f)(); }
     8 private:
     9     void (T::*f)();  // f为其成员函数指针
    10 };
    11 
    12 // 对外的接口
    13 template <class S, class T>
    14 inline mem_fun_t<S,T> mem_fun(S (T::*f)()) { 
    15     return mem_fun_t<S,T>(f);
    16 }
    View Code

    下面给出该适配器的用法:

     1 class Sharp {
     2 public:
     3     virtual void name() { cout << "sharp" << endl; }
     4 };
     5 
     6 class Triangle 
     7     : public Sharp {
     8 public:
     9     virtual void name() { cout << "triangle" << endl; }
    10 };
    11 
    12 class Rectangle
    13     : public Sharp {
    14     virtual void name() { cout << "rectangle" << endl; }
    15 };
    16 
    17 int main(int argc, char *argv[])
    18 {
    19     vector<Sharp*> coll;
    20     coll.push_back(new Sharp());
    21     coll.push_back(new Triangle());
    22     coll.push_back(new Rectangle());
    23     for_each(coll.begin(), coll.end(), mem_fun(&Sharp::name));
    24     return 0;
    25 }
    View Code
  • 相关阅读:
    UNIX/Linux打包,压缩 ,解压:
    Vertica删除历史分区数据
    在非归档模式下不能更改表空间为备份模式
    Oracle数据库文件路径变更
    impdp导入报错ORA-14460: only one COMPRESS or NOCOMPRESS clause may be specified
    IP,路由,交换基础培训记录
    Sybase 数据库新增用户,赋权
    struts2 接口如何接收客户端提交的json数据
    JavaWeb 发送get请求
    JavaWeb 发送post请求的2种方式(form、json)
  • 原文地址:https://www.cnblogs.com/runnyu/p/6012431.html
Copyright © 2011-2022 走看看