C++中的reverse_iterator迭代器结构设计

2024-05-04 22:44

本文主要是介绍C++中的reverse_iterator迭代器结构设计,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

reverse_iterator迭代器结构设计

reverse_iterator迭代器基本结构设计

operator*()函数

operator++()函数

operator->()函数

operator!=()函数

rbegin()函数

rend()函数

operator--()函数

operator==()函数

测试代码

const_reverse_iterator迭代器设计

reverse_iterator迭代器结构设计思路改进


reverse_iterator迭代器结构设计

前面的list类以及vector类设计了正向迭代器,现在考虑设计反向迭代器,常规的设计思路为单独为反向迭代器建一个新类,这个类中所有的函数全部重新设计,这种思路可取但是并不高效,可以考虑下面的设计思路:

前面了解到了容器适配器,那么是否也可以把正向迭代器设置为反向迭代器的容器适配器从而实现反向迭代器的效果

对于此时的反向迭代器类设计即为如下:

以list类为例

reverse_iterator迭代器基本结构设计

//反向迭代器template<classIterator>class_list_reverse_iterator{typedef_list_reverse_iterator self;//使用正向迭代器构造反向迭代器_list_reverse_iterator(Iterator it):_it(it){}​private:Iterator_it;};

operator*()函数

首先是对于operator*()函数来说,解引用操作符获得的结果即为指针当前指向中的内容,而在正向迭代器中,解引用操作符也是同样的作用,所以此处可以复用正向迭代器的解引用操作符,但是此处是Iterator类对象,所以不能使用传统的直接对内置类型解引用的方式,但是可以考虑直接调用Iterator类中的operator*()函数

对于返回值来说,可以考虑和设计const版本的正向迭代器思路一致,使用模板参数区分传递T&T*

所以修改原来的类定义为:

//反向迭代器template<class Iterator, class Ref, class Ptr>class _list_reverse_iterator{typedef _list_reverse_iterator self;//使用正向迭代器构造反向迭代器_list_reverse_iterator(Iterator it):_it(it){}​private:Iterator _it;};

此时的operator*()函数即为如下设计:

//operator*()函数Ref operator*(){return _it.operator*();}

operator++()函数

对于前置++运算符来说,不同于正向迭代器,因为正向迭代器++是从第一个有效数据节点开始一直到头节点结束,而对于反向迭代器来说,其++是从最后一个有效数据节点开始向前一直到头节点结束,如下图所示:

但是可以考虑通过正向迭代器适配出反向迭代器,具体思路如下:

begin()放置在最后一个有效数据节点的位置,即end()-1的位置,将end()放在头节点的位置即可

所以,operator++()函数可以设计为

//operator++()函数
self& operator++()
{--_it;return *this;
}

operator->()函数

operator*()函数一样,调用Iterator中的operator->()函数即可

//operator->()函数Ptr operator->(){return _it.operator->();}

operator!=()函数

同正向迭代器中的设计思路一致

//operator!=()函数
bool operator!=(self& s)
{return _it != s._it;
}

rbegin()函数

//rbegin()函数——反向——非const版本
reverse_iterator rbegin()
{//因为正向迭代器中没有重载-,所以使用--代替return reverse_iterator(--end());
}

rend()函数

//rend()函数——反向——非const版本
reverse_iterator rend()
{return reverse_iterator(end());
}

operator--()函数

//operator--()函数
self& operator--()
{++_it;return *this;
}

operator==()函数

//operator==()函数
bool operator==(const self& s)
{return _it == s._it;
}

测试代码

此时基本的反向迭代器框架已经搭建完成,下面是测试代码:

void test_reverse_iterator()
{sim_list::list<int> ls;ls.push_back(1);ls.push_back(2);ls.push_back(3);ls.push_back(4);ls.push_back(5);sim_list::list<int>::reverse_iterator rit = ls.rbegin();while (rit != ls.rend()){cout << *rit << " ";++rit;}
}

const_reverse_iterator迭代器设计

对于const_reverse_iterator设计来说,不需要更改reverse_iterator迭代器的结构,只需要在list类中重定义一个const版本即可

typedef _list_reverse_iterator<iterator, T&, T*> reverse_iterator;// 反向迭代器——非const版本
typedef _list_reverse_iterator<iterator, const T&, const T*> const_reverse_iterator // 反向迭代器——const版本

并且将rbegin()rend()分别重载一个const版本

//rbegin()函数——反向——const版本
reverse_iterator rbegin() const
{//因为正向迭代器中没有重载-,所以使用--代替//注意end()此处是常量,但是此处是调用了operator--(),所以可以调用(编译器对const类型能调用普通函数的优化),如果是内置指针类型则必须写成end()-1return reverse_iterator(--end());
}//rend()函数——反向——const版本
reverse_iterator rend() const
{return reverse_iterator(end());
}

reverse_iterator迭代器结构设计思路改进

前面在设计reverse_iterator迭代器时,直接考虑的rbegin()函数的位置在最后一个有效节点的位置,而rend()在则在end()的位置,这样的思路并没有错误,但是参照SGI版本中的设计:

rbegin()rend()设计

可以看出,SGI版本在设计rbegin()rend()时考虑到和begin()end()形成了一种对称关系,如下图所示:

那么此时SGI版本中的反向迭代器是如何处理operator*()函数的

配合rbegin()rend()遍历思路如下:

取出上一个有效节点的数据,因为rbegin()在头节点的位置,所以先取出最后一个节点的数据,迭代器--操作到最后一个有效节点,一直到rend()位置结束

参考完SGI版本的迭代器设计,此时可以对上面的设计进行优化为SGI版本

//operator*()函数
Ref operator*()
{Iterator cur = _it;//如果不实现--,也可以用-1来代替return *(--cur);
}//rbegin()函数——反向——非const版本
reverse_iterator rbegin()
{//因为正向迭代器中没有重载-,所以使用--代替return reverse_iterator(end());
}//rend()函数——反向——非const版本
reverse_iterator rend()
{return reverse_iterator(begin());
}//rbegin()函数——反向——const版本
reverse_iterator rbegin() const
{//因为正向迭代器中没有重载-,所以使用--代替return reverse_iterator(end());
}//rend()函数——反向——const版本
reverse_iterator rend() const
{return reverse_iterator(begin());
}

此时对于operator->()函数来说,则需要换一个实现思路:直接取当前operator*()结果的地址

//operator->()函数
Ptr operator->()
{return &(operator*());
}

这篇关于C++中的reverse_iterator迭代器结构设计的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/960254

相关文章

c++ 类成员变量默认初始值的实现

《c++类成员变量默认初始值的实现》本文主要介绍了c++类成员变量默认初始值,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录C++类成员变量初始化c++类的变量的初始化在C++中,如果使用类成员变量时未给定其初始值,那么它将被

C++中NULL与nullptr的区别小结

《C++中NULL与nullptr的区别小结》本文介绍了C++编程中NULL与nullptr的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编... 目录C++98空值——NULLC++11空值——nullptr区别对比示例 C++98空值——NUL

C++ Log4cpp跨平台日志库的使用小结

《C++Log4cpp跨平台日志库的使用小结》Log4cpp是c++类库,本文详细介绍了C++日志库log4cpp的使用方法,及设置日志输出格式和优先级,具有一定的参考价值,感兴趣的可以了解一下... 目录一、介绍1. log4cpp的日志方式2.设置日志输出的格式3. 设置日志的输出优先级二、Window

Java设计模式---迭代器模式(Iterator)解读

《Java设计模式---迭代器模式(Iterator)解读》:本文主要介绍Java设计模式---迭代器模式(Iterator),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录1、迭代器(Iterator)1.1、结构1.2、常用方法1.3、本质1、解耦集合与遍历逻辑2、统一

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

C++20管道运算符的实现示例

《C++20管道运算符的实现示例》本文简要介绍C++20管道运算符的使用与实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录标准库的管道运算符使用自己实现类似的管道运算符我们不打算介绍太多,因为它实际属于c++20最为重要的

Visual Studio 2022 编译C++20代码的图文步骤

《VisualStudio2022编译C++20代码的图文步骤》在VisualStudio中启用C++20import功能,需设置语言标准为ISOC++20,开启扫描源查找模块依赖及实验性标... 默认创建Visual Studio桌面控制台项目代码包含C++20的import方法。右键项目的属性:

c++中的set容器介绍及操作大全

《c++中的set容器介绍及操作大全》:本文主要介绍c++中的set容器介绍及操作大全,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录​​一、核心特性​​️ ​​二、基本操作​​​​1. 初始化与赋值​​​​2. 增删查操作​​​​3. 遍历方

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决

C++11委托构造函数和继承构造函数的实现

《C++11委托构造函数和继承构造函数的实现》C++引入了委托构造函数和继承构造函数这两个重要的特性,本文主要介绍了C++11委托构造函数和继承构造函数的实现,具有一定的参考价值,感兴趣的可以了解一下... 目录引言一、委托构造函数1.1 委托构造函数的定义与作用1.2 委托构造函数的语法1.3 委托构造函