反向迭代器的++即正向迭代器的--,反向迭代器的--即正向迭代器的++,反向迭代器和正向迭代器的很多功能都是相似的,因此我们可以复用正向迭代器作为反向迭代器的底层容器来封装,从而实现出反向迭代器,即:反向迭代器内部可以包含一个正向迭代器,对正向迭代器的接口进行包装
这样一来我们可以实现任意容器的反向迭代器,如果用的是vector的正向迭代器,那么就封装出vector的反向迭代器,如果用的是list的正向迭代器,那么就封装出list的反向迭代器,这就是迭代器适配器了
反向迭代器:
template<class Iterator,class Ref,class Ptr>
class ReverseIterator
{typedef ReverseIterator<Iterator, Ref, Ptr> Self;
public:ReverseIterator(Iterator it):_it(it){}Self& operator++(){--_it;return *this;}Self operator++(int){Self tmp(*this);--_it;return tmp;}Self& operator--(){++_it;return *this;}Self operator--(int){Self tmp(*this);++_it;return tmp;}Ref operator*()//返回前一个位置的数据{Iterator cur = _it;return *(--cur);}Ptr operator->(){return &(operator*());}bool operator!=(const Self& s){return _it != s._it;}bool operator==(const Self& s){return _it == s._it;}private:Iterator _it;
};
库中设计的反向迭代器与正向迭代器是对称关系,关于解引用越界问题也很巧妙的处理了~:
解引用返回的是前一个位置的数据
vector模拟实现:
#include<assert.h>
#include"Reverseiterator.h"
namespace djx
{template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;typedef ReverseIterator<iterator, T&, T*> reverse_iterator;typedef ReverseIterator<const_iterator, const T&, const T*> const_reverse_iterator;reverse_iterator rbegin(){return reverse_iterator(end());}reverse_iterator rend(){return reverse_iterator(begin());}const_reverse_iterator rbegin() const{return const_reverse_iterator(end());}const_reverse_iterator rend() const{return const_reverse_iterator(begin());}iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin()const{return _start;}const_iterator end()const{return _finish;}vector()//一定要写,因为我们已经写了拷贝构造了,编译器不会生成默认的构造函数,当要使用无参的构造时如果我们没写,就没有,会报错{}vector(const vector<T>& v){reserve(v.capacity());for (auto& e : v){push_back(e);}}vector(size_t n, const T& val = T()){reserve(n);for (size_t i = 0; i < n; i++){push_back(val);}}template <class InputIterator>vector(InputIterator first, InputIterator last){while (first != last){push_back(*first);first++;}}void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endofstorage, v._endofstorage);}vector<T>& operator=(vector<T> tmp){swap(tmp);return *this;}~vector(){delete[] _start;_start = _finish = _endofstorage = nullptr;}T& operator[](size_t pos){assert(pos < size());return _start[pos];}const T& operator[](size_t pos) const{assert(pos < size());return _start[pos];}void reserve(size_t n){if (n > capacity()){size_t sz = size();T* tmp = new T[n];if (_start){for (size_t i = 0; i < sz; i++){tmp[i] = _start[i];}delete[] _start;}_start = tmp;_finish = _start + sz;_endofstorage = _start + n;}}void push_back(const T& val){/* if (_finish == _endofstorage){reserve(capacity() == 0 ? 4 : capacity() * 2);}*_finish = val;_finish++;*/insert(end(), val);//复用insert}void resize(size_t n, const T& val = T()){if (n <= size()){_finish = _start + n;}else{reserve(n);while (_finish < _start + n){*_finish = val;_finish++;}}}void insert(iterator pos, const T& val){assert(pos >= _start);assert(pos <= _finish);if (_finish == _endofstorage){size_t len = pos - _start;reserve(capacity() == 0 ? 4 : capacity() * 2);pos = _start + len;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;end--;}*pos = val;_finish++;}iterator erase(iterator pos){assert(pos >= _start);assert(pos < _finish);iterator begin = pos + 1;while (begin < _finish){*(begin - 1) = *begin;begin++;}_finish--;return pos;}size_t capacity() const{return _endofstorage - _start;}size_t size()const{return _finish - _start;}private:iterator _start = nullptr;//都会走构造,拷贝构造的初始化列表iterator _finish = nullptr;//给缺省值,就不用我们在构造,拷贝构造函数的初始化列表给值iterator _endofstorage = nullptr;};
}
测试vector的反向迭代器:
void func(const djx::vector<int>& v)
{djx::vector<int>::const_reverse_iterator rit = v.rbegin();while (rit != v.rend()){cout << *rit << " ";rit++;}cout << endl;
}int main()
{djx::vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);djx::vector<int>::reverse_iterator rit = v.rbegin();while (rit != v.rend()){cout << *rit << " ";rit++;}cout << endl;func(v);return 0;
}
list模拟实现:
#include"Reverseiterator.h"
namespace djx
{template<class T>struct list_node{T _data;list_node<T>* _prev;list_node<T>* _next;list_node(const T& x = T()):_data(x), _prev(nullptr), _next(nullptr){}};template<class T, class Ref, class Ptr>struct __list_iterator{typedef list_node<T> Node;typedef __list_iterator<T, Ref, Ptr> self;Node* _node;__list_iterator(Node* node):_node(node){}Ref operator*(){return _node->_data;}Ptr operator->(){return &_node->_data;}self& operator++(){_node = _node->_next;return *this;}self operator++(int){self tmp(*this);_node = _node->_next;return tmp;}self& operator--(){_node = _node->_prev;return *this;}self operator--(int){self tmp(*this);_node = _node->_prev;return tmp;}bool operator!=(const self& s){return _node != s._node;}bool operator==(const self& s){return _node == s._node;}};template<class T>class list{typedef list_node<T> Node;public:typedef __list_iterator<T, T&, T*> iterator;typedef __list_iterator<T, const T&, const T*> const_iterator;typedef ReverseIterator<iterator, T&, T*> reverse_iterator;typedef ReverseIterator<const_iterator, const T&, const T*> const_reverse_iterator;reverse_iterator rbegin(){return reverse_iterator(end());}reverse_iterator rend(){return reverse_iterator(begin());}const_reverse_iterator rbegin()const{return const_reverse_iterator(end());}const_reverse_iterator rend() const{return const_reverse_iterator(begin());}iterator begin(){return _head->_next;}iterator end(){return _head;}const_iterator begin()const{return _head->_next;}const_iterator end()const{return _head;}void empty_init(){_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;}list(){empty_init();}list(const list<T>& lt){empty_init();for (auto e : lt){push_back(e);}}void swap(list<T>& lt){std::swap(_head, lt._head);std::swap(_size, lt._size);}list<T>& operator=(list<T> lt){swap(lt);return *this;}~list(){clear();delete _head;_head = nullptr;}void clear(){iterator it = begin();while (it != end()){it = erase(it);}}void push_back(const T& x){insert(end(), x);}void push_front(const T& x){insert(begin(), x);}void pop_back(){erase(--end());}void pop_front(){erase(begin());}iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* newnode = new Node(x);Node* prev = cur->_prev;prev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;_size++;return newnode;}iterator erase(iterator pos){Node* cur = pos._node;Node* next = cur->_next;Node* prev = cur->_prev;delete cur;prev->_next = next;next->_prev = prev;_size--;return next;}size_t size(){return _size;}private:Node* _head;size_t _size;};
}
测试list的反向迭代器:
void func(const djx::list<int>& lt)
{djx::list<int>::const_reverse_iterator rit = lt.rbegin();while (rit != lt.rend()){cout << *rit << " ";rit++;}cout << endl;
}int main()
{djx::list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);djx::list<int>::reverse_iterator rit = lt.rbegin();while (rit != lt.rend()){cout << *rit << " ";rit++;}cout << endl;func(lt);return 0;
}
当然了,我们也可以按照不同于库中设计的逻辑来设计反向迭代器:但是存在一些细节需要处理
与库中反向迭代器设计模式不同之处在于解引用的设计
上图版本的反向迭代器解引用重载的设计:
Ref operator*(){return *_it}
那么,相应的在vector和list中也会发生变化:
vector中:
reverse_iterator rbegin(){return reverse_iterator(end() - 1);}reverse_iterator rend(){return reverse_iterator(begin() - 1);}const_reverse_iterator rbegin() const{return const_reverse_iterator(end() - 1);}const_reverse_iterator rend() const{return const_reverse_iterator(begin() - 1);}
需要注意的是必须是end()-1 /begin()-1 而不能是--end()/--begin()
因为vector类中迭代器的实现,我们将其设计为原生指针T*,是内置类型
end()/begin() 为传值返回,返回的是临时对象,具有常性,不可被修改
list中:
reverse_iterator rbegin(){return reverse_iterator(--end());}reverse_iterator rend(){return reverse_iterator(end());}const_reverse_iterator rbegin() const{return const_reverse_iterator(--end());}const_reverse_iterator rend() const{return const_reverse_iterator(end());}
也可以设计成end()-1,只不过list的正向迭代器是自定义类型,需要重载-运算符才可
那么问题就来了,为什么同样是各自的--end() ,vector就报错,我们知道因为返回的是临时对象具有常性导致的,但是list却不报错可以这样设计呢?
诚然,list的end()返回的也是临时对象,同样具有常性,不报错是因为这是特殊情况,特殊处理:具有常性的自定义类型的对象可以调用非const的函数
所以list中的--end()返回的自定义类型的临时对象可以调用list迭代器类中,非const的--运算符重载函数
如:
class A
{
public:A(int x = 0):_a(x){}void Print(){}private:int _a;
};
我们有时候会写出这样的代码:
A(1).Print(); // 特殊处理
A(1)是匿名对象具有常性,而print函数是非const的