大家好呀~欢迎进入我的这篇学习笔记~ 我的上一篇C++文章传送点在这里哦:【C++】stack、queue、priority_queue的模拟实现_柒海啦的博客-CSDN博客
我们知道,在C++的STL容器中,有着一个重要的迭代器,也就是和正向迭代器不一样的反向迭代器。这篇学习笔记,将带大家认清理清楚反向迭代器如何通过正向迭代器进行复用实现,达到一个多种容器都能使用的结果。
废话不多说,我们直接开始吧:
目录
1.引入
2.代码实现
3.综合代码
4.测试vector和list
在前面,相信大家也见识过了容器适配器。实际上就是在复用STL的其他容器的时候,搞得一个模板参数进行替代,能够做到用不同的容器进行底层实现。只要底层所调用的方法一致就不会出现问题,但是效率问题就要看用户本身是如何去想的了。
实际上,反向迭代器的实现也就是迭代器适配器的实现。我们只需要控制传入一个正向迭代器,根据此正向迭代器的相同调用完成反向迭代器,已达到不同的容器均可以使用此反向迭代器类模板,只要实现了正向迭代器的类似功能。
比如我们写一个反向迭代器,让list和vector都能够使用此反向迭代器。(list的正向迭代器封装过,vector的正向迭代器是原生指针)
要执行反向迭代器,实际上也就是完成和正向迭代器相反的功能(也可以直接写一个反向迭代器,直接使用容器底层的结构,但是这样并没有复用,并且也打不到适配器的效果),正向迭代器++对应反向的--,--对应反向的++,其余类似。
如上图所示,每个容器对自己的数据进行一个封装成正向迭代器,使其能像指针那样去访问数据。而反向迭代器无需关系容器内部数据结构,只需要正向迭代器提供相应的功能我来进行封装即可。
首先,此反向迭代器自然是模板类,首先是类似于正向迭代器封装实现模板的那一套,T&和T*分开传入。只不过此时数据不再是类型T,而是iterator:
// iterator T& T*
template
定义成struct方便全部设置为public,方便访问,类名和库一致:__reverse_iterator。成员自然就是我们的正向迭代器,把自身调用重命名一下(后面有些接口需要传出自己)
// iterator T& T*
template
struct __reverse_iterator
{
Iterator _cur;
typedef __reverse_iterator reverse_iterator;
......
}
构造函数需要传入一个正向迭代器,初始化给我们的成员变量:
__reverse_iterator(Iterator it)
:_cur(it)
{}
++和--分别调用正向迭代器的--和++即可:
reverse_iterator& operator++()
{
--_cur;
return *this;
}
reverse_iterator operator++(int)
{
reverse_iterator tmp(_cur);
--_cur;
return tmp;
}
reverse_iterator& operator--()
{
++_cur;
return *this;
}
reverse_iterator operator--(int)
{
reverse_iterator tmp(_cur);
++_cur;
return tmp;
}
解引用需要注意,因为此时第一个传入的应该是end(rbegin),即反向迭代器是从正向迭代器的end开始遍历,而end是指向数据最后一个的下一个位置,所以我们要在不改变此时所在位置的情况下,访问前一个位置的数据即可:
Ref operator*()
{
Iterator tmp = _cur;
--tmp;
return *tmp;
}
->表示指针访问某个成员所用符号,所以我们应该返回指针即地址,所以就复用上面的取值,然后取地址即可:
Ptr operator->()
{
return (&operator*());
}
!= 和 == 直接复用正向迭代器的即可:
bool operator!=(const reverse_iterator& r)
{
return _cur != r._cur;
}
bool operator==(const reverse_iterator& r)
{
return _cur == r._cur;
}
#pragma once
// 实现反向迭代器配置 利用原本的迭代器作为容器
namespace YuShen
{
// iterator T& T*
template
struct __reverse_iterator
{
Iterator _cur;
typedef __reverse_iterator reverse_iterator;
__reverse_iterator(Iterator it)
:_cur(it)
{}
reverse_iterator& operator++()
{
--_cur;
return *this;
}
reverse_iterator operator++(int)
{
reverse_iterator tmp(_cur);
--_cur;
return tmp;
}
reverse_iterator& operator--()
{
++_cur;
return *this;
}
reverse_iterator operator--(int)
{
reverse_iterator tmp(_cur);
++_cur;
return tmp;
}
Ref operator*()
{
Iterator tmp = _cur;
--tmp;
return *tmp;
}
Ptr operator->()
{
return (&operator*());
}
bool operator!=(const reverse_iterator& r)
{
return _cur != r._cur;
}
bool operator==(const reverse_iterator& r)
{
return _cur == r._cur;
}
};
}
分别在list和vector导入后,进行测试:
vector的具体模拟实现链接在这里哦~:【C++】vector从理解到深入_柒海啦的博客-CSDN博客
测试代码:
可以发现,测试的非常成功。明明两个正向迭代器的底层实现都不相同(一个封装实现,一个原生指针)。其实我们发现反向迭代器的实现利用的都是接口罢了。所以,只要正向迭代器提供相同的接口(++ -- 随机访问等等.....),就能统一的进行实现,此反向迭代器也就有了它作为模板类的意义。