放在专栏【C++知识总结】,会持续更新,期待支持
本章相关文章:
【STL】容器适配器
【STL】list的模拟实现
【STL】vector的模拟实现
1、反向迭代器介绍
1.1、前言
在前文中我们已经讲过STL中的适配器概念,即在底层将一个类的接口转化为另一个类的接口,并根据此设计模式模拟实现了stack与queue。本篇文章将讲解的是适配器的另一种模式——迭代器适配器(iterator adapters)之反向迭代器。
1.2、反向迭代器
我们都知道迭代器作为STL六大组件之一,主要目的是为了可以像原生指针一样,实现对容器成员的遍历和访问。但是我们在此之前所讲的以及实现的都是从前往后的正向迭代器。而反向迭代器则与正向迭代器的遍历方向相反,从后往前反向遍历。既然作为一种适配器模式,反向迭代器的实现肯定离不开正向迭代器,事实上也确实如此,反向迭代器的操作实际上底层都调用的是正向迭代器与之对应的接口。
2、模拟实现
这里由于库中实现的较为复杂,涉及到的一些操作实现(萃取等)起来较为难以理解,在这里我们只是简单的对其实现即可。同时在我们对其实现完成后,我们可以将其用在不同的支持反向遍历的容器中使用。
2.1、反向迭代器的基本结构
既然作为一种适配器模式,反向迭代器的实现肯定离不开正向迭代器,所以该类的成员变量中需要存在一个正向迭代器,同时我们在实现时采用与正向迭代器相同的处理方式即:采用多参数模板完成const与非const版本共用同一份代码。如下为其基本结构:
2.1.1、构造函数
构造函数的实现很简单,直接根据传入的参数进行构造即可:
2.1.2、++与--
反向迭代器的遍历与正向迭代器完全相反,正向迭代器的++操作,是从前往后的,因此对于反向迭代器来说就相当于自己的--操作(反向迭代器的方向是从后往前)。而正向迭代器的--操作,是从后往前的,因此对于反向迭代器来说就相当于自己的++操作。如下所示:
2.1.3、* 运算符重载
在实现对*的重载之前,我们首先要了解一下反向迭代器的结构,在STL中,反向迭代器是与正向迭代器一一对应,如下所示:
但是呢,这里就出现了一个问题,因为在SGI版本的STL中,迭代器区间有一个习惯,即:前闭后开。但是这里对于反向迭代器来说,rbegin指向的是最后一个有效元素的下一个,而rend指向的是第一个有效元素。就成了前开后闭。因此,为了实现符合前闭后开的习惯,这里对反向迭代器指针实际指向的内容做了修改,使每一个位置的指向都往“前”移动一个单位(对于反向迭代器来说就是往后),这样就符合了“前闭后开”的要求。
反向迭代器的往后,实际就是正向的往前,因此这里如下实现:
2.1.4、-> 运算符重载
这里也是与*相同,也要满足前闭后开的要求,而我们上方对*的重载已经实现了返回前一个指向的内容,这里我们只需要对其复用,取其返回值的地址即可:
2.1.5、==与!=
依然底层调用正向迭代器对应的==与!=的重载:
至此我们的简易版本的反向迭代器就实现完毕了,我们发现,我们底层的所有接口其实都是调用了正向迭代器的对应接口,而这就是适配器模式的主要体现:将一个类的接口转化成另一个类相关对应的接口来满足所实现的需求。
3、反向迭代器的应用
3.1、应用于list
这里我们可以对其进行使用,我们可以放在我们前文所实现的list中使用:在使用时需包含我们这里写的反向迭代器的头文件,同时在list中实现rbegin与rend,我们在上文已经讲过了,rbegin与end对应,rend与begin对应:
接下来我们对其进行测试:
3.2、应用于vector
当然,我们也可以将我们写的反向迭代器放到vector中去用,用法相同:
同样,我们进行测试:
至此我们之前所写的list与vector都支持了反向迭代器版本。
源码全部放在个人gitee,<<点击跳转>>
end.
生活原本沉闷,但跑起来就会有风!🌹