一、反向迭代器构造方式
1. 正向迭代器
我们知道正向迭代器的设计:begin迭代器指向第一个数据,end迭代器指向最后一个数据的下一个位置 。
迭代器++,移向下一个数据,解引用得到数据的值。
根据容器储存方式的不同,容器有不同类型的迭代器。
2. 反向迭代器
注意:rbegin迭代器指向最后一个数据的下一个位置,rend迭代器指向第一个数据,这里就体现了镜像对称,正向与反向迭代器成为对称关系。
可是,如果按照rebegin指向的位置,第一次解引用得到的应该是随机值,这是有问题的,那么stl解决方案是什么呢?它采用的方法是:解引用得到的是rebegin迭代器前一个位置的数据
为了简便,反向迭代器采用的是适配器模式,适配正向迭代器,反向迭代器的++将调用正向迭代器的--,反之亦然。
例如:
二、反向迭代器模板
我们给出统一的反向迭代器模板,对于各容器,由模板实现各自的迭代器。给模板什么正向迭代器,它就适配出相应容器的反向迭代器
#pragma once
namespace my_ReverseIterator
{
template<class Iterator, class Ref, class Ptr>
struct ReverseIterator
{
typedef ReverseIterator<Iterator, Ref, Ptr> self;
Iterator _it;
ReverseIterator(Iterator it)
:_it(it)
{}
Ref operator*()
{
Iterator tmp = _it;
return *(--tmp); //这里没有模板类型,该返回什么类型呢?1. 萃取 2. 使用者在模板处给出
}
Ptr operator->()
{
return &(operator*());
//还可以写成
//Iterator tmp = _it;
//return &(*--tmp);
}
self& operator++()
{
--_it;
return *this;
}
self& operator--()
{
++_it;
return *this;
}
bool operator!=(const self& s) const
{
return _it != s._it;
}
};
}
成员变量
- 反向迭代器采用适配器模式,将iterator类型变量作为反向迭代器类的成员变量(同stack、queue、priotiry_queue的构造方法一样)
- 后两个模板类型与Iterator模板类型相同,用于不同权限的返回值,
- Ref:T& 或 const T&
- Ptr: T* 或 const T*
#pragma once
namespace my_ReverseIterator
{
template<class Iterator, class Ref, class Ptr>
struct ReverseIterator
{
typedef ReserveIterator<Iterator, Ref, Ptr> self;
//成员变量
Iterator _it;
};
}
operator*
- 根据STL的构造,返回--后迭代器指向的数据
- *(--tmp)实际上是调用了iterator类内部的operator*()函数,返回迭代器指向的数据的值
Ref operator*()
{
Iterator tmp = _it;
return *(--tmp); //这里没有模板类型,该返回什么类型呢?1. 萃取 2. 使用者在模板处给出
}
operator->
- 同Iterator的operator->()设计思想,该函数是为了防止数据类型不是单一数据,可能是类或结构体,含有多数据时只有解引用是不够用的,是错误的
- 可以返回 &(operator*()) 也可返回 &(*--_tmp),&(*--_tmp)表示的是:--tmp后,先调用tmp的operator*()函数,得到数据的值(可能是结构体,即自定义类型,也可能是单一的数据,即内置类型),再取地址即可
Ptr operator->()
{
//Iterator tmp = _it;
//return &(*--tmp);
return &(operator*());
}
operator++ && operator--
- 前置的++或--
- 返回引用,是因为*this表示的是反向迭代器这个类实例化的对象,它的生命周期是不在该operator++或--类内部的,所以可以返回引用
self& operator++()
{
--_it;
return *this;
}
self& operator--()
{
++_it;
return *this;
}
operator!=
- 反向迭代器的比较,比较低是成员变量iterator,比较iterator时,又会转换为iterator重载的operator!=函数
- 形参const修饰反向迭代器,常引用权限,外部的const是修饰 *this,表示不可修改this指针里的内容
bool operator!=(const self& s) const
{
return _it != s._it;
}
三、补充之前模拟实现的容器反向迭代器设计
我们补充上list、vector容器的迭代器
1. list
要将ReverseIterator头文件展开在list模拟实现的文件中,并展开命名空间域,这样编译器才会识别ReverseIterator这个类型
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;
//用 end 适配 rbegin
reverse_iterator rbegin()
{
return reverse_iterator(end());
}
//用 begin 适配 rend
reverse_iterator rend()
{
return reverse_iterator(begin());
}
iterator begin()
{
//由指针类型隐式转换为iterator类
//return _head->_next;
//也可以用匿名对象
return iterator(_head->_next);
}
iterator end()
{
return iterator(_head);
}
2. vector
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());
}
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
其余容器也相同,读者可自行添加
总结:
反向迭代器也是适配器模式,这是重点,使用 end() 适配 rbegin(),begin() 适配 rend()。
我们搞清楚,这些类之间的关系,简单的一个*或!=它的背后都可能是运算符重载,简单的=可能是调用默认生成的赋值运算符重载而实现的
最后,如果小帅的本文哪里有错误,还请大家指出,请在评论区留言(ps:抱大佬的腿),新手创作,实属不易,如果满意,还请给个免费的赞,三连也不是不可以(流口水幻想)嘿!那我们下期再见喽,拜拜!