反向迭代器
反向迭代器的概念
反向迭代器是一种特殊的迭代器,简单的理解就是他与正向迭代器移动的方向正好相反,即:
- 反向迭代器的
++
= 正向迭代器的--
- 反向迭代器的
--
= 正向迭代器 的++
在使用STL的时候我们会接触到许多反向迭代器的接口,例如:
这些接口返回的类型都是反向迭代器类型,这些接口一般封装在STL容器中。
下面来看一下封装在反向迭代器类中的成员函数:
这里唯一要注意的就是operator*
的指向问题,关于这个问题,我们首先要了解rbegin()
和rend()
的指向
rend()
和rbegin()
正好与begin()
和end()
的指向相反,但是在operator*()
函数上两种迭代器就不一样了
- 正向迭代器:
operator*()
返回值就是当前迭代器所指向的元素 - 反向迭代器
operator*()
返回值就是当前迭代器所指向的前一个元素
这样做的原因是为了方便遍历:
int main()
{
vector<int> s = { 1,2,3,4,5,6,7,8,9 };
auto it = s.begin();
while (it != s.end())
{
cout << *it << ' ';
it++;
}
cout << endl;
auto is = s.rbegin();
while (is != s.rend())
{
cout << *is << ' ';
is++;
}
}
反向迭代器的实现
反向迭代器实现实际上是一种适配器模式,我们知道迭代器的实现是要知道不同容器底层的实现,从而才能实现各种运算符重载,所以一般封装在容器代码的内部,然而反向迭代器与正向迭代器存在强相连关系,所以反向迭代器可以写成封装正向迭代器的适配接口。
namespace sht
{
//ref 是数据结构里面数据类型的引用,可以理解为T&
//Ptr 是数据类型的地址,可以理解为T*
// 反向迭代器的rbegin = 正向迭代器的 begin
//反向迭代器的rend = 正向迭代器的 end
template<class iterator, class Ref,class Ptr> //这里由于不会迭代器萃取,所以把类型也传进来了,实际源码实现只用传第一个参数
class reverse_iterator
{
typedef reverse_iterator<iterator, Ref, Ptr> Self;
public:
reverse_iterator(iterator it)
:_it(it)
{
}
Ref operator*() //返回迭代器指向的前一个元素
{
iterator tmp = _it;
return *(--tmp); //正是因为begin =rend end=rbegin 所以这里解引用时正向迭代器的解引用运算符会对tmp的合法性进行检查
}
Ptr operator->()
{
return &(operator*());
}
Self& operator++()
{
--_it;
return *this;
}
Self& operator--()
{
++_it;
return *this;
}
bool operator!=(const Self& t) const
{
return _it != t._it;
}
bool operator==(const Self& t) const
{
return _it == t._it;
}
private:
iterator _it;
};
}
由于反向迭代器封装了正向迭代器,反向迭代器的构造,拷贝都是调用正向迭代器的构造和拷贝,所以完全可以不知道stl容器的底层实现,只需专注两种迭代器的逻辑关系,这就是反向迭代器的设计巧妙之处。但是这里要求正向迭代器要有完整的构造,拷贝,负值重载函数,不然反向迭代器就无法实现。
在复用的时候只需要引用该头文件即可,这里给出反向迭代器在string模拟实现的代码:string模拟实现