C++设计模式_21_Iterator 迭代器(理解;面向对象的迭代器已过时;C++中使用泛型编程的方式实现)
Iterator 迭代器也是属于“数据结构”模式。GoF中面向对象的迭代器已经过时,C++中目前使用泛型编程的方式实现,其他语言还在使用面向对象的迭代器。
文章目录
- 1. 动机(Motivation)
- 2. 模式定义
- 3. Iterator 迭代器代码分析
- 4. 面向对象的迭代器与泛型编程实现的迭代器的对比
- 5. 结构( Structure )
- 6. 要点总结
- 7. 其他参考
1. 动机(Motivation)
- 在软件构建过程中,集合对象内部结构常常变化各异。但对于这些集合对象,我们希望在不暴露其内部结构的同时,可以让外部客户代码透明地访问其中包含的元素;同时这种“透明遍历”也为同一种算法在多种集合对象上进行操作”提供了可能。
不关心内部实现结构,一种算法可以应用到树形结构,也可以应用到链表、堆、栈的结构
- 使用面向对象技术将这种遍历机制抽象为“迭代器对象”为“应对变化中的集合对象”提供了一种优雅的方式。
2. 模式定义
提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露(稳定)该对象的内部表示。
----《设计模式》GoF
GoF中最早提出面向对象对象的方式实现迭代器,但是在讲面向对象的方式之前,需要重点说一下,这种方式在C++今天来讲已经过时了,因为学过STL泛型编程的都知道泛型编程中存在迭代器,思想与今天所讲的是一样的,都是通过一种接口的方式来隔离算法和容器之间的变化,但是GoF当初定义是面向对象的方式来定义的。
3. Iterator 迭代器代码分析
整体代码:
template<typename T>
class Iterator
{
public:virtual void first() = 0;virtual void next() = 0;virtual bool isDone() const = 0;virtual T& current() = 0;
};template<typename T>
class MyCollection{public:Iterator<T> GetIterator(){//...}};template<typename T>
class CollectionIterator : public Iterator<T>{MyCollection<T> mc;
public:CollectionIterator(const MyCollection<T> & c): mc(c){ }void first() override {}void next() override {}bool isDone() const override{}T& current() override{}
};void MyAlgorithm()
{MyCollection<int> mc;Iterator<int> iter= mc.GetIterator();for (iter.first(); !iter.isDone(); iter.next()){cout << iter.current() << endl;}}
代码分析:
首先来看GoF定义的代码,面向对象的方式
template<typename T>
class Iterator
{
public:virtual void first() = 0;virtual void next() = 0;virtual bool isDone() const = 0;virtual T& current() = 0;
};
first()提供第一个元素;next()是往下一个元素走;isDone() 代表到头了;T& current()是取你当前的一组;有些设计会将next()和T& current()合二为一。
template<typename T>
class MyCollection{public:Iterator<T> GetIterator(){//...}};
MyCollection是自己定义的集合,会返回一个属于我这个集合的迭代器
template<typename T>
class CollectionIterator : public Iterator<T>{MyCollection<T> mc;
public:CollectionIterator(const MyCollection<T> & c): mc(c){ }void first() override {}void next() override {}bool isDone() const override{}T& current() override{}
};
继承Iterator抽象类,对纯虚函数进行实现,一般实现的时候需要将集合传递进来CollectionIterator(const MyCollection<T> & c): mc(c){ }
到具体使用的时候
void MyAlgorithm()
{MyCollection<int> mc; //塞一个类型Iterator<int> iter= mc.GetIterator(); //拿到迭代器//进行遍历操作for (iter.first(); !iter.isDone(); iter.next()){cout << iter.current() << endl;}}
4. 面向对象的迭代器与泛型编程实现的迭代器的对比
当我们说到面向对象时,多态是其特征。像刚才说,这种面向对象的设计已经过时,就因为泛型编程,STL库在98年出来之后,大家一对比发现,面向对象的实现方式具有很多的缺点,具体来说最核心的缺点就出在面向对象上,面向对象的方式都是虚函数调用,虚函数都是有性能成本的,要绕虚表指针找到函数地址,需要二次指针的间接运算,每次都这样做,当进行遍历操作时,数据假如有10万个元素,这个循环造成的成本就差了很多。
//进行遍历操作for (iter.first(); !iter.isDone(); iter.next()){cout << iter.current() << endl;}
98年之后的C++泛型编程中使用到的迭代器是使用模板来描述的,而模板也是一种多态技术,其实现的多态是编译式多态,即编译器在编译的时候会遍析具体的源代码,但是虚函数是运行时多态,运行时多态性能要低于编译时多态,因为编译时已经把工作做了,运行时直接调用源代码,不需要计算函数地址,因此以STL为标准的泛型编程广泛使用的是基于模板的多态迭代器,性能高于虚函数面向对象的迭代器。
而且第二个,泛型编程里有很多种迭代器,迭代器的接口发展出了更多的可能性,上面的写法只支持往前走(next()),不支持往回走(back()),我们知道泛型编程里迭代器可以++往前,--往后走,这些通过虚函数实现也可以,但是成本很高。模板的灵活性基于隐式约束,可以利用++、–操作符做为接口描述,面向对象只有虚函数一种。事实也证明,有了泛型编程的迭代器,大家再也不会用面向对象的迭代器。
但是上面所写的设计思路在其他语言,比如java,C#等得等到了极大的应用(基于运行时的多态),其他语言不支持编译时的模板体制。
5. 结构( Structure )

上图是《设计模式》GoF中定义的Iterator 迭代器的设计结构。结合上面的代码看图中对应关系如下图。

6. 要点总结
-
迭代抽象:访问一个聚合对象的内容而无需暴露它的内部表示。
-
迭代多态:为遍历不同的集合结构提供一个统一的接口,从而支持同样的算法在不同的集合结构上进行操作。
-
迭代器的健壮性考虑:遍历的同时更改迭代器所在的集合结构,会导致问题。
7. 其他参考
C++设计模式——迭代器模式
相关文章:
C++设计模式_21_Iterator 迭代器(理解;面向对象的迭代器已过时;C++中使用泛型编程的方式实现)
Iterator 迭代器也是属于“数据结构”模式。GoF中面向对象的迭代器已经过时,C中目前使用泛型编程的方式实现,其他语言还在使用面向对象的迭代器。 文章目录 1. 动机(Motivation)2. 模式定义3. Iterator 迭代器代码分析4. 面向对象的迭代器与泛型编程实现…...
有一个 3*4 的矩阵,找出其中值最大的元素,及其行列号
1解题思路: 首先学会输入二维数组;然后知道如何比较求最大值;最后就是格式问题; 2代码: #include<stdio.h> int main() {int a[3][4];int i,j,max,row,line;for(i0;i<3;i){printf("请输入二维数组\n&…...
磁盘的命令
目录 1- 磁盘空间命令1.1 df1.2 du只想查看目录的权限 加 -d 参数 1- 磁盘空间命令 1.1 df 全称 disk free 快速获取磁盘被占用了多少空间, 目前还剩下所少空间 常用命令df -hdf 是从总体上统计系统各磁盘的占用情况,不能统计具体的文件夹或文件的大小 1.2 du 全称 disk u…...
一张图讲清楚业务稳定性要如何做:SRE体系化稳定性方案
概述:作为一个SRE、运维工程师,当我们在治理系统稳定性时,方法有很多,但往往无从下手。本文以一张逻辑图的形式,为读者提供治理稳定性的体系化思路。 先上图: 1、治理目标 我们做稳定性的目标,…...
安卓端GB28181设备接入模块如何实现实时位置订阅(MobilePosition)
技术背景 实时位置(MobilePosition)订阅和上报,对GB28281设备接入终端尤其重要,如移动单兵设备、执法记录仪、智能安全帽、车载终端等,Android国标接入设备通过获取到实时经纬度信息,按照一定的间隔上报到…...
11.与JavaScript深入交流-[js一篇通]
文章目录 1.变量的使用1.1基本用法1.2理解 动态类型 2.基本数据类型2.1number 数字类型2.1.1数字进制表示2.1.2特殊的数字值 2.2string 字符串类型2.2.1基本规则2.2.2转义字符2.2.3求长度2.2.4字符串拼接 2.3boolean 布尔类型2.4undefined 未定义数据类型2.5null 空值类型 3.运…...
Ubuntu 搭建 DHCP ivp6 server 步骤
Ubuntu 搭建 DHCP ivp6 server 步骤 安装 DHCP server安装 radvd(实现局域网路由功能)测试运行 安装 DHCP server apt 安装 isc-dhcp-server sudo apt-get install isc-dhcp-server修改配置文件 /etc/dhcp/dhcpd6.conf 内容如下: lease-time 7200; lo…...
分享大数据分析师前景怎么样? 从事行业有哪些?
数据分析师发展前景和待遇怎么样?有前途吗?好找工作吗?根据某招聘网数据显示,当前市场表现为: 2023年较2022年同期对比增长160%,2022年较2021年下降了46%。 工资待遇:2023年较2022年下降了2…...
通过wordpress能搭建有影响力的帮助中心
wordpress建站服务是一种提供简单易用的工具和功能,帮助用户轻松创建和管理网站的服务。它适用于各类网站管理员、个人博主和小型企业主,无论是想要搭建个人博客、展示作品集还是开设在线商店,都可以通过wordpress建站服务来实现。 | 一、搭建…...
word页脚设置,页脚显示第几页共有几页设置步骤
word页脚设置,页脚显示第几页共有几页设置步骤: 具体步骤: 步骤1: 步骤1.1选择页脚---空白页脚 步骤1.2,在"[在此处键入]",直接输入你需要的格式,如 “第页/共页” 步骤1.3选择第“…...
C语言实现斐波那契数列的多种方法
斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”。对于解决此类问题方法有四,前两…...
一文解决:Swagger API 未授权访问漏洞问题
Swagger 是一个用于设计、构建、文档化和使用 RESTful 风格的 Web 服务的开源软件框架。它通过提供一个交互式文档页面,让开发者可以更方便地查看和测试 API 接口。然而,在一些情况下,未经授权的访问可能会导致安全漏洞。本文将介绍如何解决 …...
Elasticsearch下载安装,IK分词器、Kibana下载安装使用,elasticsearch使用演示
首先给出自己使用版本的网盘链接:自己的版本7.17.14 链接:https://pan.baidu.com/s/1FSlI9jNf1KRP-OmZlCkEZw 提取码:1234 一般情况下 Elastic Search(ES) 并不单独使用,例如主流的技术组合 ELK(…...
springboot自定义404页面
添加配置类 import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import javax.servlet.Servlet; import org.apache.catalina.startup.Tomcat; import org.apache.catalina.valves.ErrorReportValve; import org.apache.coyote.UpgradeProtoc…...
C/C++数据结构之时间复杂度和空间复杂度详细解析以及力扣刷题
个人主页:点我进入主页 专栏分类:C语言初阶 C语言程序设计————KTV C语言小游戏 C语言进阶 C语言刷题 数据结构初阶 欢迎大家点赞,评论,收藏。 一起努力,一起奔赴大厂。 目录 1.前言 2.算法的…...
【需要理解】80 单词搜索
单词搜索 题解1 回溯(需要改变起点) 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。 单词必须按照字母顺序,通过相邻的单元格内…...
笔记本电脑的键盘鼠标如何共享控制另外一台电脑
环境: 联想E14 x2 Win10 across 2.0 问题描述: 笔记本电脑的键盘鼠标如何共享控制另外一台电脑 解决方案: 1.下载across软件,2台电脑都按装,一台设为服务端,一台客户端 2.把配对好设备拖到右边左侧…...
【计算机网络】(谢希仁第八版)第二章课后习题答案
第二章 1.物理层要解决哪些问题?物理层的主要特点是什么? 答:物理层要解决的主要问题: (1)物理层要尽可能地屏蔽掉物理设备和传输媒体,通信手段的不同,使数据链路层感觉不到这些差…...
笔记软件Notability mac中文版软件功能
Notability mac是一款帮助用户备注文件的得力工具,Notability Mac版可用于注释文稿、草拟想法、录制演讲、记录备注等。它将键入、手写、录音和照片结合在一起,便于您根据需要创建相应的备注。 Mac Notability mac中文版软件功能 将手写,照片…...
【C++的OpenCV】第十四课-OpenCV基础强化(三):Mat元素的访问之data和step属性
🎉🎉🎉 欢迎来到小白 p i a o 的学习空间! \color{red}{欢迎来到小白piao的学习空间!} 欢迎来到小白piao的学习空间!🎉🎉🎉 💖 C\Python所有的入门技术皆在 我…...
React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...
新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用
文章目录 一、背景知识:什么是 B-Tree 和 BTree? B-Tree(平衡多路查找树) BTree(B-Tree 的变种) 二、结构对比:一张图看懂 三、为什么 MySQL InnoDB 选择 BTree? 1. 范围查询更快 2…...
毫米波雷达基础理论(3D+4D)
3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文: 一文入门汽车毫米波雷达基本原理 :https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...
OD 算法题 B卷【正整数到Excel编号之间的转换】
文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的:a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...
算术操作符与类型转换:从基础到精通
目录 前言:从基础到实践——探索运算符与类型转换的奥秘 算术操作符超级详解 算术操作符:、-、*、/、% 赋值操作符:和复合赋值 单⽬操作符:、--、、- 前言:从基础到实践——探索运算符与类型转换的奥秘 在先前的文…...
leetcode73-矩阵置零
leetcode 73 思路 记录 0 元素的位置:遍历整个矩阵,找出所有值为 0 的元素,并将它们的坐标记录在数组zeroPosition中置零操作:遍历记录的所有 0 元素位置,将每个位置对应的行和列的所有元素置为 0 具体步骤 初始化…...
