手搓反向迭代器

前言

关于反向迭代器,字如其名,就是将正向迭代器,从反方向再迭代一次就成了,所以我们如此设计反向迭代器:

  1. 假设我们已经拥有了一套能够使用,且包含模板的正向迭代器
  2. 利用适配器模式,让反向迭代器封装正向迭代器
  3. 利用模板的设计,让反向迭代器可以适应多种类型

统一使用规范

对于正向迭代器,为了确保各种容器使用时的统一性(名字统一,操作统一),我们常用typedef 来更改名字、用运算符重载来更改运算规则,达到使用时的统一。而反向迭代器也是如此

例:

正向:typedef __list_iterator<T,T&,T*> iterator;

反向:typedef Reverse_iterator<iterator, T&, T*> reverse_iterator;

这里是自定义实现的list的正向/反向迭代器,由于原生指针不满足所需,所以对原生指针进行了封装,封装成了__list_iterator类,给他取名叫iterator
然后再一步对正向迭代器进行封装,形成了反向迭代器,给他取名叫reverse_iterator
这个有3个模板参数:template<class Iterator,class Ref,class Ptr>,这3个参数会在后文说明

正向:typedef T* iterator;

反向:typedef Reverse_iterator<iterator, T&, T*> reverse_iterator;

这是定义的vector的正向/反向迭代器,由于其在存储空间上是连续的,所以原生指针就可以满足正向迭代器的需求,所以给T*取名叫iterator
然后再一步对正向迭代器进行封装,形成了反向迭代器,取名叫reverse_iterator


迭代器的模板参数

template<class iterator,class Ref,class Ptr>

class iterator

iterator是该反向迭代器封装的正向迭代器的类型,所以理论上该反向迭代器可以适用于任何正向迭代器。

class Ref

对于反向迭代器内部的某些操作,可能需要返回T&,所以除了iterator这一模板参数外,还要添加一个引用类型的模板参数Ref(reference)。

class Ptr

有些操作可能需要返回T*,所以增加了Ptr这一模板参数
例:这里的reverse_iterator传的参就是对应上面的参数

		typedef __list_iterator<T,T&,T*> iterator;
		typedef __list_iterator<T,const T&,const T*> const_iterator;
		typedef Reverse_iterator<iterator, T&, T*> reverse_iterator;
		typedef Reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;

运算符重载的各种实现

反向迭代器的构造函数

由于反向迭代器只需要封装一个元素:iterator,所以他的成员变量只有一个

    Iterator _it;
    Reverse_iterator(Iterator it)
        :_it(--it)
        { }

他的构造函数则如上表示,原因如下图

在这里插入图片描述

对于反向迭代器,它采用的是rend()rbegin(),这也是常用的取法
rend():等价于begin()
rbegin():等价于end()
但是由于rbegin()的位置并不是最后一个元素所在的位置,并且非有效位,所以在初始化构造的时候就需要对正向迭代器进行 - - 操作,使得其指向最后一个有效位

operator++ && operator- -

对于这一对运算符,他们要做的正好和符号相反,++要实现的实际上是正向迭代器的- -,所以实现起来也很简单,反向迭代器的++调用正向迭代器的- -,反向迭代器的–调用正向迭代器的++

	self& operator++()//前置++
	{
		--_it;
		return *this;
	}
	self operator++(int)//后置++。由于返回值是一个临时变量,所以不能引用返回
	{
		self cur = _it;
		_it--;
		return cur;
	}
	self& operator--()
	{
		++_it;
		return *this;
	}
	self operator--(int)
	{
		self cur = _it;
		_it++;
		return cur;
	}

operator* && operator-> && operator== && operator!=

这些运算符的实现需求都与正向迭代器相同,所以他们只需要调用正向迭代器的对应操作就可以实现

	Ref operator*()
	{
		return *_it;
	}
	bool operator!=(const self& tmp)
	{
		return _it != tmp._it;
	}
	bool operator==(const self& tmp)
	{
		return _it == tmp._it;
	}
	Ptr operator->()
	{
		return _it.operator->();//这里的_it的实现是:return &xxx;有取地址符,返回的是一个指针
	}

operator[]

该运算符对list无用(没有实现 [ ] 重载的情况下),但是对vector、string…有用

其作用就是返回该容器某个位置的引用

	Ref operator[](size_t pos)
	{
		return *(_it + pos);
	}

这里是对存储空间连续的结构,去找到pos位置的元素,并对其解引用,返回该点的引用。

如果非要实现对存储空间不连续的结构,需要重载其 [ ] ,然后上述重载仍然适用

反向迭代器代码

template<class Iterator, class Ref, class Ptr>
struct Reverse_iterator
{
	typedef Reverse_iterator<Iterator, Ref, Ptr> self;
	Reverse_iterator(Iterator it)
		:_it(--it)
	{ }

	Iterator _it;
	Ref operator[](size_t pos)
	{
		return *(_it + pos);
	}
	self& operator++()
	{
		--_it;
		return *this;
	}
	self operator++(int)
	{
		self cur = _it;
		_it--;
		return cur;
	}
	self& operator--()
	{
		++_it;
		return *this;
	}
	self operator--(int)
	{
		self cur = _it;
		_it++;
		return cur;
	}
	Ref operator*()
	{
		return *_it;
	}
	bool operator!=(const self& tmp)
	{
		return _it != tmp._it;
	}
	bool operator==(const self& tmp)
	{
		return _it == tmp._it;
	}
	Ptr operator->()
	{
		return _it.operator->();
	}
};
  • 18
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值