北京怀柔网站制作摄影师常用的网站

pingmian/2025/10/9 6:10:01/文章来源:
北京怀柔网站制作,摄影师常用的网站,大连网页设计学校,企业网站icp是什么C#xff1a;迭代器的封装思想 list迭代器实现反向迭代器实现 本博客将通过实现list的迭代器#xff0c;以及它的反向迭代器#xff0c;来帮助大家理解迭代器的底层逻辑#xff0c;以及封装思想。 list迭代器实现 迭代器是一个遍历容器的工具#xff0c;其可以通过自增自… C迭代器的封装思想 list迭代器实现反向迭代器实现 本博客将通过实现list的迭代器以及它的反向迭代器来帮助大家理解迭代器的底层逻辑以及封装思想。 list迭代器实现 迭代器是一个遍历容器的工具其可以通过自增自减来改变位置通过解引用来访问节点也就是模仿指针的行为。这为算法库提供了统一的方式来访问容器也降低了用户的学习成本可以用相同的方式来访问不同的容器。 那么迭代器是如何做到模仿指针行为的 这还要归功于运算符重载这一设计在类中我们可以通过运算符重载来决定一个类在面对不同运算符时的行为那么我们是否可以将迭代器封装为一个类然后利用运算符重载使得迭代器可以使用–*这样的操作符从而模仿指针的行为呢 STL的底层迭代器就是利用这样的方式实现的。 我们先来看到list的基本结构 list节点 template class T struct list_node {list_nodeT* _next;list_nodeT* _prev;T _data; };这是一个list的节点list_node其有三个成员_prev指向上一个节点_next指向下一个节点_data存储当前节点的数据。 template class Tclass list{typedef list_nodeT node;private:node* _head;};这是一个list类其将节点list_nodeT重命名为了node方便后续使用。 唯一一个成员变量是哨兵位头节点指针_head。 接下来我们就讨论要如何设计这个list的迭代器 毫无疑问我们需要把这个迭代器封装为一个类而这个类的内部我们需要什么才能让迭代器访问不同的节点呢 想要访问不同的节点毫无疑问就需要不同节点的指针所以我们的迭代器需要把一个指向节点的指针给封装起来然后利用运算符重载改变这个指针的行为从而实现迭代器。 现在我们将这个迭代器命名为__list_iterator先看看基础结构 template class T struct __list_iterator {typedef list_nodeT node;node* _node; };为了方便我们使用节点的指针我们重命名list_nodeT为node而迭代器内部指向节点的指针名为_node。 构造函数 代码如下 __list_iterator(node* n): _node(n) {}这就是一个很简单的初始化过程这里不过多赘述了那么我们要如何使用这个迭代器呢 看看list类中获取迭代器的函数 typedef __list_iteratorT iterator;iterator begin() {return iterator(_head-_next); }iterator end() {return iterator(_head); }先将我们的迭代器重命名为iterator方便后续使用。 可以看到我们的begin()函数就是返回了哨兵位节点的后一个节点也就是第一个节点的指针但是普通的指针的–操作不符合我们的要求于是我们利用iterator(_head-_next)这个方式利用这个指针来构造一个匿名对象也就是迭代器的匿名对象此时我们就完成了指针的封装得到的指针就是被我们修改了行为后的迭代器了。 end()函数同理iterator(_head)构造一个迭代器将指针进行封装修改其行为。 接下来我们回到迭代器的实现 operator 我们希望我们的迭代器可以在的时候到达下一个节点的位置也就是_node _node-_next这样的行为。 所以我们的需求就明确了当迭代器的时候实际发生的是_node _node-_next而不是简单的指针偏移。 先看到我们的实现 __list_iteratorT operator() {_node _node-_next;return *this; }是要进行返回的将自增后的节点作为返回值所以最后我们还要return *this;将修改后的节点作为返回值。 后置同理 __list_iteratorT operator(int) {__list_iteratorT tmp(*this);_node _node-_next;return tmp; }由于后置需要将自增前的值作为返回值所以我们要先拷贝一份原先的值tmp自增完成后将原先的值tmp返回。 为了简化代码我们可以将__list_iteratorT重命名为self代表迭代器自己的类型。 最后代码如下 typedef __list_iteratorT self;self operator() {_node _node-_next;return *this; }self operator(int) {self tmp(*this);_node _node-_next;return tmp; }这样一来我们的迭代器表面上和指针自增一样但是底层却是_node _node-_next到达下一个节点的位置了。 operator– 迭代器–同理我们需要实现迭代器到达上一个节点其实就是_node _node-_prev。 实现如下 self operator--() {_node _node-_prev;return *this; }self operator--(int) {self tmp(*this);_node _node-_prev;return tmp; }迭代器判断相等 想要判断两个迭代器是否相等其实就是判断其内部封装的指针_node是否相等。 代码如下 bool operator!(const self s) {return _node ! s._node; }bool operator(const self s) {return _node s._node; }这个比较简单不做赘述了。 operator* *是迭代器中十分重要的操作符指针就是利用解引用来访问指向内容的迭代器就模仿指针也通过解引用来访问节点值。 迭代器内部的成员_node是指向节点的指针那么访问这个节点的值就是_node-_data了。 所以解引用代码如下 T operator*() {return _node-_data; }但是这个代码有一个问题那就是如果我们的list被const修饰了怎么办 这样的话由于我们返回的是T而这个_data就有可能会被修改这就不符合const的行为了。 是否我们要写一个重载比如这样 T operator*() {return _node-_data; }const T operator*() {return _node-_data; }这是不行的因为两个函数只有返回值不同并不构成重载。 我们只希望返回值的类型不同这要怎么办 注意我们的迭代器是利用模板生成的而模板最大的用处就是泛型编程可以无视类型的限制我们完全可以给模板多传一个参数让第二个参数作为operator*的返回值。 //-----迭代器----- template class T, class Ref struct __list_iterator {typedef __list_iteratorT, Ref self;Ref operator*(){return _node-_data;} };这样当我们需要普通迭代器第二个参数Ref就传入T如果需要const迭代器那么第二个参数就传入const T。 不过要注意的是刚刚我们重命名了一个self 即typedef __list_iteratorT self此时由于模板参数改变这个重命名也要一起改变typedef __list_iteratorT, Ref self。 现在我们就可以在list中加入const迭代器了接下来让类中定义的迭代器一起改变 template class T class list {typedef __list_iteratorT, T iterator;typedef __list_iteratorT, const T const_iterator;//普通迭代器iterator begin(){return iterator(_head-_next);}iterator end(){return iterator(_head);}//const迭代器const_iterator begin() const{return const_iterator(_head-_next);}const_iterator end() const{return const_iterator(_head);} };看到两行typedef typedef __list_iteratorT, T iterator; typedef __list_iteratorT, const T const_iterator;当我们传入的第二个模板参数为T那么解引用的返回值就是可以修改的此时就是一般的迭代器iterator。 当我们传入的第二个模板参数为const T那么解引用的返回值就是不可以修改的此时就是const迭代器const_iterator。 相比于开始我们现在多了一个迭代器const_iterator;我们的this指针被const修饰时说明此时需要调用const迭代器那么我们就返回const_iterator类型的迭代器。 const_iterator begin() const {return const_iterator(_head-_next); }const_iterator end() const {return const_iterator(_head); }operator- 接下面我们看到最后一个问题那就是类的嵌套问题假设我们的list内部是一个A类 class A { public:int num; };那么如果我们想要通过迭代器访问A类的num成员要怎么做 假设我们有一个list的迭代器it接下来我用it尝试访问这个A的成员num。 (*it).num先解引用迭代器(*it)此时就得到了list内部的A类然后再利用.来访问内部的num成员。 这样访问是没有问题的但是我们的迭代器是模仿指针的行为我们会对一个指针先解引用再用点操作符访问成员吗 我们完全可以指针 - 成员这样访问。 也就是说我们还要对迭代器重载一个-操作符实现这种直接访问的方式 代码 T* operator-() {return _node-_data; }我们的返回值是_data的地址而_data就是A类所以我们可以就得到了一个A类的指针此时T*就是其实就是A*。 那么我们看看现在要如何访问 list.operator-()-num你也许不是很能理解以上代码我们拆解一下 list.operator-()返回了一个A*类型的指针而A*类型的指针可以直接访问num A* ptr; ptr-num所以以上代码list.operator-()-num就可以访问到num这个成员了。 而.operator-()其实就是-操作符所以可以变形为以下代码 list--num 连用--不太美观也容易让人费解但是编译器会将两个-优化为一个-所以此时我们已经可以直接像指针一样访问成员了 list-num我们再回顾一遍推导过程 list.operator-()-num list--num list-num 这个访问和刚刚的operator*会遇到同样的问题那就是const问题所以我们要传入第三个模板参数Ptr来控制operator-的返回值 template class T, class Ref, class Ptr struct __list_iterator {Ptr operator-(){return _node-_data;} };在list中 typedef __list_iteratorT, T, T* iterator; typedef __list_iteratorT, const T, const T* const_iterator;至此我们就实现了一个list的迭代器了。 代码展示 template class T, class Ref, class Ptr struct __list_iterator {typedef list_nodeT node;typedef __list_iteratorT, Ref, Ptr self;node* _node;__list_iterator(node* n): _node(n){}Ref operator*(){return _node-_data;}Ptr operator-(){return _node-_data;}self operator(){_node _node-_next;return *this;}self operator(int){self tmp(*this);_node _node-_next;return tmp;}self operator--(){_node _node-_prev;return *this;}self operator--(int){self tmp(*this);_node _node-_prev;return tmp;}bool operator!(const self s){return _node ! s._node;}bool operator(const self s){return _node s._node;} };反向迭代器实现 那么我们要如何实现反向迭代器呢 一开始我们实现正向迭代器的时候遇到的问题就是原生指针的行为不符合我们的要求于是我们将原生指针进行了封装利用运算符重载来修改其行为。 那么我们的反向迭代器还需要封装一个原生指针吗 其实我们可以换一个思路现在我们有正向迭代器而正向迭代器并不符合反向迭代器的预期行为我们不妨对正向迭代器进行一次封装让其变成––变成这不就是一个反向迭代器了吗 结构如下 template class Iterator, class Ref, class Ptr struct ReverseIterator {Iterator _cur; };我们定义了一个反向迭代器的类ReverseIterator在内部封装了一个迭代器Iterator _cur接下来我们就重载这个反向迭代器让其行为符合预期 先看看我们在list中是如何定义反向迭代器的 template class Tclass list{typedef ReverseIteratoriterator, T, T* reverse_iterator;//反向迭代器reverse_iterator rbegin(){return reverse_iterator(end());}reverse_iterator rend(){return reverse_iterator(begin());}};首先我们重命名了反向迭代器typedef ReverseIteratoriterator, T, T* reverse_iterator;其第一个模板参数为iterator也就是我们封装的正向迭代器。 随后在rbegin()中我们直接将end()返回的末尾迭代器作为我们反向迭代器的起始迭代器rbegin() 将begin()返回的正向迭代器的起始迭代器作为我们反向迭代器的末尾迭代器。 注意end()返回的是最后一个元素的后面一个位置所以我们在后续,–操作时要进行其他的操作来矫正这个位置的偏差。 operator 现在由于我们是反向迭代器我们的反向迭代器其实就是正向迭代器的–。 代码如下 self operator() {--_cur;return *this; }operator* 由于我们的迭代器位置是往后偏一位的所以我们要返回前一个位置的迭代器而不是当前位置的迭代器 Ref operator*() {Iterator tmp _cur;--tmp;return *tmp; }我们用tmp拷贝了一份当前的迭代器随后--tmp将其往前走一个位置再返回tmp位置的迭代器这样就可以矫正我们起初的位置偏差了。 而其它的操作符重载几乎没有太大的差别基本就围绕以上两种类型的改动此处我们直接展示代码了 template class Iterator, class Ref, class Ptrstruct ReverseIterator{typedef ReverseIteratorIterator, Ref, Ptr self;Iterator _cur;ReverseIterator(Iterator it):_cur(it){}Ref operator*(){Iterator tmp _cur;--tmp;return *tmp;}Ptr operator-(){Iterator tmp _cur;--tmp;return tmp-_data;}self operator(){--_cur;return *this;}self operator(int){self tmp(*this);--_cur;return tmp;}self operator--(){_cur;return *this;}self operator--(int){self tmp(*this);_cur;return tmp;}bool operator!(const self s){return _cur ! s._cur;}bool operator(const self s){return _cur s._cur;}};这个反向迭代器的实现可以作用于任何正向迭代器也就是说不论是listvector等等各种容器都可以使用这一套反向迭代器来封装原本的迭代器从而获得反向迭代器

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/90341.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网上商城网站建设方案网站分栏目怎么做

文 | sliderSun源 | 知乎NLP模型的大小不断增加,随之而来的是可用性降低,TinyBERT,MobileBERT,和DistilBERT都提出了一个独特的知识蒸馏框架,其共同目标是在保持性能的同时减小模型大小。尽管所有这些方法都以各自的方…

余姚做网站哪家好易语言 做网站

1、强引用(StrongReference) 强引用不会被GC回收,并且在java.lang.ref里也没有实际的对应类型。举个例子来说:     Object obj new Object();     这里的obj引用便是一个强引用,不会被GC回收。 2、软引用&…

改变网站字体索引擎优化 seo

嘛,说实话,现在才开始,实在是有点晚了,一不小心大学都过去1年了_(:3 」∠)_ 我在专业方面的起步也是相当晚的,身为计算机专业,编程却从大学才开始正式接触,进入大学时其他方面的能力也都约等于0…

西安机场商务宾馆百度做网站哈尔滨百度网站快速优化

总的来说就是,由两台以上的路由器组成一个HSRP组,在该组之中选举一台路由器作为Active路由器,一台路由器作为Standby路由器,其它路由器则进入Listen状态。实际工作时,是由Active路由器去转发数据,一旦Activ…

哪些网站有好的营销案例重庆市建设施工安全网

docker仓库登录及配置insecure-registries的方法 这篇文章主要介绍了docker仓库登录配置insecure-registries的方法,docker客户端如果配置中添加了insecure-registary配置,就不需要在docker 客户端配置上对应证书,如果不配置要在/etc/docker/certs.d/目…

站长号小程序赚钱的几种方法

对于需要大量翻译的数据,人工翻译太慢,此时需要使用软件进行批量翻译。1.使用360的翻译def fanyi_word_cn(string):url"https://fanyi.so.com/index/search"#db_path ./db/tasks.dbForm_Data {}#这里输入要翻译的英文Form_Data[query] string…

网站开发制作流程ppt精美模板

目录 1 问题2 问题分析3 解决过程3.1 确保Pillow库存在3.2 迷惑阶段3.3 解决问题 4 希望大佬解答 1 问题 今天做了一个使用Python写的脚本文件.py,打算把它转换成.exe文件。点击生成的exe文件时,出现了如下弹窗。 2 问题分析 根据错误描述&#xff1…

网站怎么做域名跳转青岛知名网站建设公司排名

我想从Oracle的nashorn JavaScript引擎中调用一个带有 char[] 输入参数的Java函数(非数组参数类型的函数对我来说没问题) .如果我用JavaScript字符串文字调用Java函数,nashorn balksjavax.script.ScriptException: TypeError: Can not invoke method[jdk.internal.d…

免费网站建站 知乎做二手房又做网站的

一、对于三相电源线的电动机,反转只需要任意的交换两根电源线即可 二、例如接通KM1对应正转的话,则接通KM2则对应反转 三、电机正转按钮及其对应的地址 四、电机反转按钮及其对应的地址 五、电机停止按钮及其对应的地址 六、正转的接触器线圈 七、反转的…

百度网盘怎么做网站网站平台项目交接需要什么

目录 什么是TestNG? 如何创建testng.xml文件 手动创建testng.xml 通过testng.xml运行整个包 通过testng.xml运行类 使用Eclipse创建testng.xml 本文将讨论TestNG以及如何通过执行testng.xml文件在TestNG中运行第一个测试用例。 什么是TestNG? Te…

计算机 网站开发 文章wordpress首页图片管理

上次讲了常用的接口:C初阶:初识STL、String类接口详细讲解(万字解析) 今天就来进行模拟实现啦 文章目录 1.基本结构与文件规划2.构造函数(constructor)2.1构造函数2.1.1无参有参分开2.1.2利用缺省参数合起来 2.2拷贝构…

古镇高端网站建设卖货到海外的免费平台

1 介绍 Rancher是一个开源的企业级多集群Kubernetes管理平台,实现了Kubernetes集群在混合云本地数据中心的集中部署与管理,以确保集群的安全性,加速企业数字化转型。Rancher 1.0版本在2016年就已发布,时至今日,Ranche…

互联网站从事登载新闻业务管理暂行规定小视频网站怎么做

第二章 算法设计思想 一、搜索排序 1.排序算法 https://visualgo.net/zh/sorting (1)冒泡排序 # 思路: # (1)比较相邻元素,如果第一个比第二个大,则交换他们 # (2)第一轮下来,可以保证最后一个数一定是最大的;第二…

商丘网站公司济南公共资源交易中心

题意: 给你一些联通关系,问Bob先选择一些路径(1~n)联通,Alice在路径上染色,Bob的目的是选择一些路径使得染色变化最小,对于Alice来说,需要使得在Bob选择的(1−n1-n1−n&…

湖北商城网站建设怎么去除自己做的网站

文章目录 openGauss学习笔记-151 openGauss 数据库运维-备份与恢复-物理备份与恢复之gs_basebackup151.1 背景信息151.2 前提条件151.3 语法151.4 示例151.5 从备份文件恢复数据 openGauss学习笔记-151 openGauss 数据库运维-备份与恢复-物理备份与恢复之gs_basebackup 151.1 …

高新网站开发1年经验网站开发开始阶段的主要任务包括( )

当谈及安全产业,你脑海里能够想到哪些事情?是红黑大战的攻防演练,还是PC上的各种安全软件?事实上,安全的范围远超我们的想象,安全产业也一直在背后,默默的保护在互联网生活的周围。 互联网的发…

门户网站的特点及优势注册有限公司需要多少钱

众所周知,Windows系统有个传统艺能,就是通过“netplwiz”或者“control userpasswords2”设置免密码自动登录。前段时间在调整一台虚拟机的配置时,突然惊奇的发现,在设置免密码登录的时候居然找不到需要去掉勾选的复选框了。如下图…

做网站公司价格瑞昌市建设局网站

11月21日,由中国联通举办的主题为“共筑产业生态,链通数智未来”的网络安全现代产业链共链行动计划暨战新共创启航大会“5G工业互联网”专题供需对接会在北京顺利召开,宏电股份董事长左绍舟应邀出席活动。 会议现场,中国联通雁飞…

动力做网站京东商城网站开发平台

随着工程机械行业的不断发展和自动化程度的提高,工业一体机在工程机械车辆上的应用越来越广泛。工业一体机是集电脑、显示器、触摸屏、通讯、测量、控制等多种功能于一体的高度集成化的工业控制系统,在工程机械车辆上的应用可以为用户提供更为便捷、高效…

装饰网站建设多少钱多国语言网站

linux是开源系统,之所以打不开,是因为部分linux系统为了避免版权问题,没有m4a的解码插件。所以,解决的办法是安装如下两个非常小的转换器,我们一般用不到转换器的功能,而是反向应用,通过两个几十…