C++初阶—完善适配器(反向迭代器)

这篇具有很好参考价值的文章主要介绍了C++初阶—完善适配器(反向迭代器)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

C++初阶—完善适配器(反向迭代器)

目录

0. 前言

1、反向迭代器定义

2、反向迭代器需要实现的相关函数

3、反向迭代器分析

4、针对vector物理空间结构分析

5、针对list物理空间结构分析

6、反向迭代器适配器的实现及测试

7、有关迭代器的功能分类


0. 前言

本篇文章主要根据前面所实现的STL中支持迭代器的容器进行完善,使用了适配器原则,传递正向迭代器数据类型,从而实现反向迭代器。

STL六大组件中:包括容器(vector、list、queue、stack、string...)、配接器(容器适配器:queue、stack、deque和priority_queue)、迭代器(普通迭代器、const迭代器、反向迭代器、const反向迭代器)、仿函数(less、greater...)、算法(find、swap、sort、merge、reverse...)、空间配置器(allocator)!!!

1、反向迭代器定义

  1. 反向迭代器从容器的尾元素向首元素反向移动的迭代器
  2. 对于反向迭代器,其中递增递减的含义完全颠倒
  3. 递增时,会移动到前一个元素
  4. 递减时,会移动到后一个元素
  5. 解引用时,需要获取到所属位置的前一个元素
  6. ->操作时,获取前一个位置数据的地址

2、反向迭代器需要实现的相关函数

反向迭代器操作:

  • rbegin()——指向容器最后一个元素的下一个位置
  • rend()——指向首元素的位置
  • crbegin()——const反向迭代器
  • crend()——const反向迭代器

反向迭代器内部操作:

前置++、后置++、前置--、后置--、关系运算符!=、解引用*、操作符->等

3、反向迭代器分析

        在实现list容器时,由于物理空间不连续,在实现其正向迭代器时,单独封装了一个类,而string、vector存储数据的物理空间是连续的,底层操作的实际时指向数据位置的指针。

        因此,在实现反向迭代器时,难道我们要针对每个容器,在实现一个类吗?

        结合上节课容器适配器的学习,我们可以根据C++类模板,传递正向迭代器,并设置多个模板参数,用于根据所传模板参数的不同,实体为不同的类,从而实现const迭代器!!!通过传递模板参数正向迭代器,我们只需要定义一个迭代器对象,复用正向迭代器的操作即可!!!对于sting、vector会自动调用其迭代器普通操作,对于list重载操作符,自动调用其重载的操作符!!!

以上操作极大提高了反向迭代器的复用性、适配性,也可称为针对迭代器的反向迭代器适配器

4、针对vector物理空间结构分析

C++初阶—完善适配器(反向迭代器)

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

//迭代器
		reverse_iterator rbegin() {
			return reverse_iterator(end());
		}
		reverse_iterator rend() {
			return reverse_iterator(begin());
		}
		const_reverse_iterator rbegin() const {
			return const_reverse_iterator(end());
		}
		const_reverse_iterator rend() const {
			return const_reverse_iterator(begin());
		}

        通过上述代码分析,可知rbegin()指向end()位置,rend指向begin()位置,因此遍历时,rebgin()++便调用正向迭代器所重载或默认的--,当rbegin() == rend()时,遍历结束!!!

        而由于rbegin()每次指向所需数据位置的下一个位置,因此重载反向迭代器*操作时,需要使用中间变量,中间变量拷贝构造和--操作,在使用*操作,便获取到所应遍历数据位置的数据!同时也不会改变this所指向的位置!!!

        

C++初阶—完善适配器(反向迭代器)

        在使用后置++,--操作时,需要记录前一次数据的迭代器,返回所记录的迭代器,在进行正向迭代器的反向操作

5、针对list物理空间结构分析

C++初阶—完善适配器(反向迭代器)

 根据上述分析,结合list再次进行分析,rbegin()指向头节点,rend()指向头节点的下一个位置

        

    template<class T, class Ref, class Ptr>
    struct __list_iterator {
            typedef __list_node<T> list_node;
            typedef __list_iterator<T, Ref, Ptr> iterator;

            list_node* _node;

            __list_iterator(list_node* node)
                :_node(node)
            {}
            bool operator!=(const iterator& it) const {
                return _node != it._node;
            }
            bool operator==(const iterator& it) const {
                return _node == it._node;
            }

            iterator& operator++() {
                _node = _node->_next;
                return *this;
            }
            iterator operator++(int) {
                iterator temp(*this);
                _node = _node->_next;
                return temp;
            }

            iterator& operator--() {
                _node = _node->_prev;
                return *this;
            }
            iterator operator--(int) {
                iterator temp(*this);
                _node = _node->_prev;
                return temp;
            }

            //T* operator->() {
            Ptr operator->() const {
                return &(operator*());
            }
            //T& operator*() const {
            Ref operator*() const {
                return _node->_data;
            }

            //T* operator->() {
            Ptr operator->() {
                return &(operator*());
            }
            //T& operator*() const {
            Ref operator*() {
                return _node->_data;
            }
     };

        遍历时,rbegin()++即相当于end()--,通过在list正向迭代器重写的类,此时rbegin()便会反向便利、

        解引用,获取到当前节点的前一个结点的数据,直到遍历到rend()结束!!!而对rend()解引用,会获取到头结点的数据,因此反向迭代器适配器同时适用所有容器!!!

6、反向迭代器适配器的实现及测试

反向迭代器的实现:

namespace Thb {
	//复用、适配,迭代器适配器
	template<class Iterator, class Ref, class Ptr>
	struct __reverse_iterator {
		Iterator _cur;

		typedef __reverse_iterator<Iterator,Ref,Ptr> RIterator;
		__reverse_iterator(Iterator it) :_cur(it) {
		}

		RIterator& operator++() {
			_cur--;
			return *this;
		}
		RIterator& operator--() {
			_cur++;
			return *this;
		}
		RIterator operator++(int) {
			RIterator temp = *this;
			--_cur;
			return temp;
		}
		RIterator operator--(int) {
			RIterator temp = *this;
			++_cur;
			return temp;
		}

		Ref operator*() {
			Iterator temp = _cur;
			--temp;
			return *temp;
		}
		Ref operator*() const {
			Iterator temp = _cur;
			--temp;
			return *temp;
		}

		Ptr operator->() {
			return &(operator*());
			//return _cur.operator->();
		}
		Ptr operator->() const {
			return &(operator*());
			//return _cur.operator->();
		}

		bool operator!=(const RIterator& it) {
			return _cur != it._cur;
		}
	};
}

反向迭代器的测试:

#include"list.h"
#include"vector.h"
#include"stack&&queue.h"
namespace std {
	void testListReverse() {
		int arr[] = { 3,2,7,6,0,4,1,9,8,5 };
		Thb::list<int> ls(arr, arr + sizeof(arr) / sizeof(arr[0]));
		Thb::list<int>::iterator it = ls.begin();
		while (it != ls.end()) {
			cout << *it << " ";
			++it;
		}
		cout << endl;

		auto rit = ls.rbegin();
		while (rit != ls.rend()) {
			*rit += 1;
			cout << *rit << " ";
			++rit;
		}
		cout << endl;

		const Thb::list<int> ls1 = ls;
		auto crit = ls1.rbegin();
		while (crit != ls1.rend()) {
			cout << *crit << " ";
			++crit;
		}
		cout << endl;
	}
	void testVectorReverse() {
		int arr[] = { 3,2,7,6,0,4,1,9,8,5 };
		Thb::vector<int> ls(arr, arr + sizeof(arr) / sizeof(arr[0]));
		Thb::vector<int>::iterator it = ls.begin();
		while (it != ls.end()) {
			cout << *it << " ";
			++it;
		}
		cout << endl;

		auto rit = ls.rbegin();
		while (rit != ls.rend()) {
			cout << *rit << " ";
				rit++;
		}
		cout << endl;

		const Thb::vector<int> ls1 = ls;
		auto crit = ls1.rbegin();
		while (crit != ls1.rend()) {
			cout << *crit << " ";
			crit++;
		}
		cout << endl;
	}
	void testConst() {
		int arr[] = { 3,2,7,6,0,4,1,9,8,5 };
		Thb::vector<int> ls(arr, arr + sizeof(arr) / sizeof(arr[0]));

		const Thb::stack<int, Thb::vector<int>> st(ls);
		cout << st.top() << endl;
	}
}

int main() {
	try {
		std::testListReverse();
		std::cout << std::endl << std::endl << std::endl;
		std::testVectorReverse();
		std::cout << std::endl << std::endl << std::endl;
		std::testConst();
	}
	catch (const std::exception& e) {
		std::cout << e.what() << std::endl;
	}
	return 0;

7、有关迭代器的功能分类

由上实现的反向迭代器针对list、vector、sting都可实现,底层是对普通迭代器的封装,而上实现的支持++,--的迭代器又称为双向迭代器,其底层的普通迭代器需要支持++、--操作!!!

而vector、string迭代器底层是原生指针,除了支持正反遍历之外,还支持算数+、-操作,因此,这类迭代器又称为随机访问迭代器!!!

对于其他容器如forward_list(单链表)、unordered_map、unordered_set,由于其性质,只能支持向后遍历,不能进行反向遍历,因此,这类迭代器称为单项迭代器!!!

C++初阶—完善适配器(反向迭代器)

 文章来源地址https://www.toymoban.com/news/detail-493689.html

平时在使用算法库所提供的sort、reverse等查阅文档时,可以看到其模板迭代器命名风格,名称暗示你,sort的容器的迭代器是随机迭代器

C++初阶—完善适配器(反向迭代器)

 通过查看文档,可以看到针对不同容器支持的迭代器命名风格,其中箭头表示了继承关系!

C++初阶—完善适配器(反向迭代器)

 

到了这里,关于C++初阶—完善适配器(反向迭代器)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 深入篇【C++】手搓模拟实现list类(详细剖析底层实现原理)&&模拟实现正反向迭代器【容器适配器模式】

    1.一个模板参数 在模拟实现list之前,我们要理解list中的迭代器是如何实现的。 在vector中迭代器可以看成一个指针,指向vector中的数据。它的解引用会访问到具体的数据本身,++会移动到下一个数据位置上去,这些都是因为vector具有天生的优势:空间上是连续的数组,这样指

    2024年02月15日
    浏览(33)
  • 【C++初阶】容器适配器模拟实现栈和队列(附源码)

    其实在使用模板时,我们 不仅可以使用类模板,还可以使用容器模板 ,这就是一个容器适配器,我们可任意给 模板实例化不同的容器,然后就可以使用容器里的接口 。 我们知道,栈可以用数组实现也可以用链表实现,以前在C语言那里,如果我们想要两个底层不同的栈,要

    2024年02月16日
    浏览(36)
  • C++初阶:容器适配器介绍、stack和queue常用接口详解及模拟实现

    介绍完了list类的相关内容后:C++初阶:适合新手的手撕list(模拟实现list) 接下来进入新的篇章,stack和queue的介绍以及模拟: stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行元素的插入与提取操作。 stack是作为容器适配器

    2024年02月19日
    浏览(29)
  • 面试之快速学习STL-迭代适配器

    参考:http://c.biancheng.net/view/7255.html 例子: 想使用反向迭代器实现逆序遍历容器,则该容器的迭代器类型必须是双向迭代器或者随机访问迭代器。 常见操作 注意这里不能用std::list,因为它是双向迭代器, +3的操作需要随机访问迭代器 。故联想到std::list排序只能使用list提供的

    2024年02月11日
    浏览(30)
  • C++适配器模式

    1 简介: 适配器模式是一种结构型设计模式,用于将一个类的接口转换为客户端所期望的另一个接口。适配器模式允许不兼容的类能够协同工作,通过适配器类来实现接口的转换和适配。 2 实现步骤: 以下是使用C++实现适配器模式的步骤: a. 定义目标接口:首先,确定客户

    2024年02月12日
    浏览(25)
  • 适配器模式(C++)

    将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 在软件系统中,由于应用环境的变化,常常需要将“一些现存的对象 ”放在新的环境中应用,但是新环境要求的接口是这些现存对象所不满足的。 如何

    2024年02月14日
    浏览(25)
  • C++ [STL容器适配器]

    本文已收录至《C++语言》专栏! 作者:ARMCSKGT 前面我们介绍了适配器模式中的反向迭代器,反向迭代器通过容器所支持的正向迭代器适配为具有反向迭代功能的迭代器,本节我们介绍STL中另一种适配器: 容器适配器 ! 前面我们提到过STL适配器模式,关于适配器的解释: S

    2024年02月11日
    浏览(33)
  • 【C++】手撕 栈 & 队列(适配器)

    目录 一,stack 1,stack的介绍 2,stack 框架 3,push(const T x) 4,pop() 5,top() 6,size() 7,empty() 8,stack 测试 9,源代码 二,queue 1,queue的介绍 2,queue 框架 3,push(const T x) 4,pop() 5,front() 6,back() 7,size() 8,empty() 9,queue 测试 10,源代码 三,总结 1,stack 是一种容器适配器,专门用

    2024年04月15日
    浏览(22)
  • C++附加篇: 空间适配器

     \\\"我有时难过,却还有些抚慰和感动。\\\"         STL的六大组件,容器、算法、迭代器、适配器、仿函数,最后一个也就是\\\"空间适配器\\\"。         所谓\\\"空间适配器\\\",顾名思义,就是对STL中各个容器的内存进行高效的管理。也许你会说,诶,我写了这么多的C++代码,为什

    2023年04月19日
    浏览(24)
  • C++之装饰器&适配器模式

    目录 一、装饰器模式 模式思想 模式简介 模式优点 模式缺点 代码实现 情景模拟 代码实现 运行结果 二、适配器模式 模式简介 介绍 优点 缺点 代码实现 情景模拟 模式简介 装饰器模式( Decorator Pattern )允许向一个现有的对象 添加新的功能 ,同时又不改变其结构。 这种类型

    2024年02月13日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包