高级IO】③epoll实现IO多路转接
以epoll相关接口构成的高级IO 不仅是名称上类似,epoll与poll的功能也是类似的,但是按man手册的说法,epoll是为处理大批量句柄而做了改进的poll,它几乎具备了之前所介绍的select和poll构成的高级IO的一切优点,因此它被公认为Linux2.6下性能最好的多路I/O就绪通知方法 认识 epoll 系列接口epoll有3个相关的系统调用 来自头文件<sys/epoll.h> epoll_create该接口用于创建epoll实例,它的返回值我们称为epfd 1int epoll_create(int size); 根据man手册,自Linux 2.6.8之后,参数size将会被忽略,但是必须大于0 epoll_ctlepoll的事件注册函数 1int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); 这一系统用于增、改、查位于epfd对应的epoll实例内的待监听的文件描述符列表 参数描述 epfd: 由先前的epoll_create产生的epfd op: 操作代码,有如 ...
高级IO】②poll实现IO多路转接
以系统提供的函数poll为核心实现多路转接,即高级网络IO 认识 poll 函数123#include <poll.h> int poll(struct pollfd *fds, nfds_t nfds, int timeout); 特殊的结构体pollfd 12345struct pollfd { int fd; /* 文件描述符 */ short events; /* 请求事件 */ short revents; /* 应答事件 */}; 功能poll也类似于select函数,能够同时监听多个文件描述符的就绪事件 参数解释 fds是pollfd结构体数组的指针/地址,提供待监听文件描述符的列表。其中结构体中的位图提供了每个文件描述符的各种状态的可能性 nfds表示传入数组的长度 timeout表示poll函数的超时时间,单位是毫秒(ms) 其中events和revents都是位图,可以有如下取值 | 事件 | 描述 ...
为什么写博客-540天总结
前言今天是2025年的情人节,我与我的博客小站已经相互陪伴了540天啦~。人对事物的认识总是阶段性的,所以我决定是时候阶段性地回答当初遗留的问题了—-为什么写博客 我们首先回顾一下我们的博客产出经历了怎样的阶段: 建站之初: 其实一开始我只模糊地知道写博客有很多好处,自己折腾建站也主要是因为觉得有自己的博客网站很酷,于是便折腾出了一个博客网站。 难产时期:我原本并没有写文章的习惯,写博客对我来说是全新的尝试,但是根据我学习各种新东西积累下来的经验,我知道刚开始总是产出很低效率很低的。确实,一开始我写博客的效率并不高,质量也不高。但没关系,我知道,它们作为我起步的垫脚石至关重要 配图时期: 早起的博客我很少配图,因为我一直苦于找不到合适的作图软件。后来我还是下定了决心要给我的文章配上示意图,工具我就选择了我本身有一点点基础的ppt,虽然做的不快,但好在易上手,图示清晰。 系列时期: 此时我读到了一些好书,我觉得可以根据书中的内容出一些系列博客。这些书也着实成为了博客的高质量灵感来源 项目时期: 当学习到可以产出比较有规模的代码时,我的博客技术已经发展到可以自信地输出文字,和高效地利用pp ...
面向对象分析与设计(2)--对象模型
对象模型引入面向对象要素建立在很好的工程基础之上。它的要素统称为“开发对象模型”,或者简称为“对象模型”。拆开来讲,它包含如下原则: 抽象 封装 模块化 层次结构 类型 并发 持久 就它们本身来说,没有一个原则是创新的。但重要的是,在对象技术中,它将这些要素以一种相互配合的方式结合起来了。面向对象分析和设计在本质上与传统的结构化设计方法提出了一种不同的方式来解决软件问题。 对象模型的演进了解对象模型是如何诞生和一步步走向成熟的,有利于我们理解现代对象模型是如何工作的。
C++项目】美鹅外卖-总集介绍博客
项目介绍为客户提供一个C/S架构的外卖平台,使用Qt框架和cpp-httplib 等模块实现其业务功能。能够服务消费者,商家和管理员的使用需求,目前支持的平台为Windows平台。 使用的技术点有: QT界面框架 QT Json处理模块 cpp-httplib库 MySQL connector/c++ 运行环境当前版本v1.0 客户端: windows 11 服务端: windows 11 需求分析用户需求当前目标实现的用户需求有 用户注册、登录 商家添加产品 商家查看和修改产品 商家查看和处理订单 消费者查看和添加购物车 消费者查看和结算订单 消费者优惠等级变化 管理员查看销售日志 角色抽象归纳根据需求的功能点,可以将系统的参与者抽象成两层三类。 用户: 所有具体参与者的总称,更高一级的抽象 商家:提供菜品和处理订单的一类人 消费者:点餐和请求订单的一类人 管理员:有权限查看销售日志的一类人 用例图 功能需求根据用户的需求,我们提出更具体,更偏向实现的功能需求 阅读提示:点击右侧目录可以跳转 用户注册功能用户可以使用唯一的*账号名和手机号和进行账号注册 ...
C++项目】美鹅外卖-客户端实现
客户端详细设计版本信息当前版本: v0.9测试版 当前版本的界面属于类似于毛坯房的只有UI结构和功能而没有美化,且所有的图片显示均尚未处理,均使用了QLabel进行占位 用户界面设计在使用代码工具编写界面前,可以先使用作图工具设计(“画”)一个UI界面出来,这样子有助于将UI设计与代码开发有一定程度的解耦合。降低开发难度 界面流转流程图 注册界面 注册按钮: 点击请求注册 转到用户名登录按钮: 点击转到用户名登录界面 转到手机号登录按钮:点击转到手机号登录 用户名登录界面 登录按钮: 点击请求登录 转到注册按钮: 点击转到注册界面 转到手机号登录按钮:点击转到手机号登录 手机号登录界面 登录按钮: 点击请求登录 转到注册按钮: 点击转到注册界面 转到用户名登录按钮:点击转到用户名登录 账户优惠等级升级界面 升级为VIP按钮:由普通成员升级为VIP 升级为SVIP按钮:由普通成员升级为SVIP 消费者菜品列表界面 导航栏按钮: 点击切换对应界面 菜品样式图: 点击转到菜品详情窗口 菜品名 ...
protobuf实战】网络通讯录
protobuf简介Protocol Buffers 是 Google 的⼀种语⾔⽆关、平台⽆关、可扩展的序列化结构数据的⽅法,它可⽤于(数据)通信协议、数据存储等。 Protocol Buffers 类⽐于 XML,是⼀种灵活,⾼效,⾃动化机制的结构数据序列化⽅法,但是⽐XML 更⼩、更快、更为简单。你可以定义数据的结构,然后使⽤特殊⽣成的源代码轻松的在各种数据流中使⽤各种语⾔进⾏编写和读取结构数据。你甚⾄可以更新数据结构,⽽不破坏由旧数据结构编译的已部署程序。 简单来讲, ProtoBuf(全称为 Protocol Buffer)是让结构数据序列化的⽅法,其具有以下特点: 语⾔⽆关、平台⽆关:即 ProtoBuf ⽀持 Java、C++、Python 等多种语⾔,⽀持多个平台。 ⾼效:即⽐ XML 更⼩、更快、更为简单。 扩展性、兼容性好:你可以更新数据结构,⽽不影响和破坏原有的旧程序 使用特点 安装protobuf下载 ProtoBuf 前⼀定要安装依赖库:autoconf automake libtool curl make g++ unzip 安装命令如下 对于Ubunt ...
C++项目】美鹅外卖平台的服务端实现
服务端详细设计版本信息当前版本: v0.9测试版 当前版本的服务器使用了如下技术栈: QT框架: 利用QT的全平台特性,这里的开发环境也使用了QT框架。主要使用了QT里的数据结构 QT Json框架: 本版本对报文的序列化与反序列化技术依然使用了Json格式 cpp-httplib:一个开源的单文件的http库,用于提供简单易操作的短链接HTTP服务 MySQL Connector/C++ Windows平台: MySQL官方提供的Windows平台C++连接数据库的API HTTP请求路径约定客户端与服务端的交互对具体函数的调用,取决于HTTP 请求路径的约定,所以要提前约定好 账户相关 Account API 路径 业务 /account/register 账户注册 /account/login/username 账户使用用户名登录 /account/login/phone 账户使用手机号登录 /account/update/level 消费者账户优惠等级更新 /account/update/nickname 账号更新昵称 消费者相关 Consu ...
高级IO】①select实现IO多路转接
以系统提供的函数select为核心实现多路转接,即高级网络IO 认识select函数1234#include <sys/select.h>int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); 功能select系统调用能够同时监测多个文件描述符的状态变化,这个系统调用是阻塞式的,退出阻塞等待的条件是被监视的文件描述符中有一个或多个发生了变化。 参数解释 nfds: 文件描述符数组长度,值为最大的文件描述符值+1。因为文件描述符从0开始 readfds: 本质上是位图,表示待监视的可读文件描述符的集合,返回时标记发生变化的fd writefds: 本质上是位图,表示待监视的可写文件描述符集合,返回时标记发生变化的fd exset: 本质上是位图,表示待监视的异常文件描述符的集合,返回时标记发生变化的fd timeout: 用于设置select()的等待时间 struct timeval 12345678910struc ...
设计模式的C++实现(7)——组合模式Composite
模式名称: 组合模式类型: 结构型问题-使用场景: 可用于构建对象树这样的部分-整体层次结构,使用户对单个对象和组合对象的使用具有一致性解决方案: 使用递归组合的方式构建类效果: 使用户对单个对象和组合对象的使用具有一致性 样例引入如下图,有过QT开发经验的朋友能够看出来,这是QT组件管理里的对象树,它是一种管理组件的数据结构,同时它也很好地体现了组合模式在实际应用中的作用。 实现方式我们可以通过继承和聚合配合使用的方式实现组合模式,就以模拟实现上图的QWidget为例,我们来设计一个自己SWidget使之能够达到类似的效果 我们设计的类图如下 可以看到,在类图中,SObject和SWidget既是继承关系,又有组合关系,这一结构特点使SWidget之间能够构成对象树,而SLabel也是SObject的子类,但由于没有聚合关系,所以SLabel在对象树中仅能作为”叶子节点”存在。 代码实现如下,我们成功构建了一颗三层的对象树。 1234567891011121314151617181920212223242526272829303132333435363738394041424 ...
8086汇编】迭代-手把手教你实现递归求斐波那契数和无符号数字的输出
概述本期的重点在于使用8086汇编语言实现循环迭代,无符号数字输出,使用多位内存储存超长整型,超长整型打印输出 程序框图 模块图 初始化准备我们先把代码段、数据段和栈段准备好相关的数据并完成相关的初始化 声明段我们先声明三个段 1assume cs:codesg,ds:datasg,ss:stacksg 装载数据在数据段我们准备填入如下数据 choose 字符串,用于输出提示信息 result 字符串,用于输出提示信息 enter 字符串,用于输出回车换行,即\n\r pressQ 字符串,用于输出退出程序的提示信息 wrongRange 字符串,用于输出范围错误的提示信息 num1 12字节长整型,表示迭代中的Fib(n-2) num2 12字节长整型,表示迭代中的Fib(n-1),同时最终答案也存在num2中 numlen 单字(2字节)变量,储存输出数字串的长度/栈的深度 tmpcx1 单字变量,辅助暂存cx的值,避免使用栈,防止栈的管理混乱 这里写入num我们使用dw指令写入一个字长(2字节) 而写入字符串必须一个字节一个字节写入,所以使用db指令 特别的, ...
设计模式的C++实现(6)——适配器Adapter/包装器-Wrapper
模式名称: 适配器-Adapter,又称包装器-Wrapper类型: 结构型问题-使用场景: 适配器可以让原本由于接口不兼容而不能一起工作的类可以重新一起工作解决方案:使用适配器对象对原本的类进行继承或者对类的对象进行组合并调用接口两种方式效果:在无需知晓,且不改变已有类的源码的前提下,使系统能够耦合在一起进行工作 实现方式Adapter主要有两种实现方式。 继承 组合 两种方式各有利弊,虽然可能组合方式居多 应用举例现在我们要做一个绘图编辑器,我们用Shape抽象类规定了子类控件的行为,而我们又有了一个成品的工具类TextView,它本身提供了显示文本的接口,但我们不知道它的源码,或者不愿意修改它的源码,因此我们无法让TextView满足Shape的规定接口要求,二者无法直接一起工作。 所以为了复用TextView,我们可以选择使用适配器模式,构造一个TextShape子类继承自Shape,同时组合了一个TextView实例化出的对象text,这样也可以调用TextView里的接口。这样通过TextShape作为适配器,我们成功地让接口能够间接兼容了。 下图为例子的类图, ...
【8086汇编】递归-手把手教你实现递归求斐波那契数和无符号数字的输出
概述本期的重点在于使用8086汇编语言实现函数递归,无符号数字输出 程序框图 模块图 初始化准备我们先把代码段、数据段和栈段准备好相关的数据并完成相关的初始化 声明段我们先声明三个段 1assume cs:codesg,ds:datasg,ss:stacksg 装载数据在数据段我们准备填入如下数据 num表示我们要求斐波那契数列的第num个数 choose 字符串,用于输出提示信息 result 字符串,用于输出提示信息 enter 字符串,用于输出回车换行,即\n\r 这里写入num我们使用dw指令写入一个字长(2字节) 而写入字符串必须一个字节一个字节写入,所以使用db指令 特别的,在8086中,$用于表示一段字符串的结尾 1234567;初始化数据段,并填入数字datasg segment num dw 10h ;选择斐波那契数列的第num个数 choose db 'Please choose a num from 1 to 100 : ','$' result db 'The result is : & ...
深入理解传输层协议UDP/TCP
传输层负责接收应用层的数据并通过网络层发送到网络的另一端。主要的传输层协议就是UDP和TCP协议 再谈端口号因为传输层要和网络层打交道,常常要使用IP和端口号,IP协议我们以后再详谈,我们先再深入学习下端口 端口是网络协议中的概念,是一个uint16_t的无符号整型,范围是0~65535,显然还是一个有限资源。 端口号划分 0~1023: 知名端口号,HTTP,FTP,SSH等这些常用的应用层协议会固定使用里面的端口号 1024~65535:操作系统动态分配的端口号。客户端自动分配的端口号就在这个范围。 知名端口号为了方便使用,人们约定了常用的服务器使用固定的端口号 服务器类型 端口号 SSH 22 FTP 21 telnet 23 HTTP 80 HTTPS 443 UDP协议全称 User Datagram Protocol, 即用户数据报协议 格式UDP协议的格式十分简单,就是固定的8字节报头,组成结构如下 UDP长度这一部分的值表示整个报文的长度,单位是字节,包括UDP报头和数据段。16位UDP长度支持的最大长度是64K 然而64KB在如今 ...
初识计网应用层协议HTTP
应用层数据组织与传输我们所写的提供网络服务的程序都是运行在应用层上的。在这些程序中,我们往往会使用结构体、类和对象等结构化的方式组织数据 但是在使用socket api接口时,我们只能使用字符串/字节流的格式来发送/接收信息,实现网络通信。但是对于提到的结构化数据,又该怎么使用网络通信传输呢? 应用层协议针对应用层内的通信问题,我们依然使用协议解决。只要发送方和接收方按照同一’约定’对结构化数据进行字节流编码和字节流解析,就能够实现通过网络进行通信。这样的约定就是 协议。 既然协议是一种约定,那么就能开发出各种各样的的应用层协议。但它们往往会用到序列化和反序列化技术,所以我们先了解一下什么是序列化和反序列化 序列化与反序列化这一技术能够在对象(结构化数据)和字节流之间架起桥梁,使对象能够更方便地支持网络通信,或者文件持久化。简单来说序列化就是基于某种规则把对象/结构化数据转化成字节流,反序列化就是基于同样的规则,把字节流还原成对象/结构化数据。 相关的序列化格式可以自己定义,当然也可以直接使用别人封装好的现成的格式。就比如常见的JSON,XML,YAM ...
【功能更新v1.4】同步&异步⽇志系统Sink类主题更新,新增数据库落地,及重大bug修复
本次版本更新我们采用Sink类主题更新,实现数据库落地,按小时按天滚动输出,网络输出,以及标准输出按等级染色 重大bug修复修改前的代码 12345678910void error(const char*file,size_t line,const char*fmt,...){ if(shouldLog(LogLevel::Level::ERROR) == false) return; va_list al; va_start(al,fmt);//依据fmt从内存中提取可变参数列表 log(LogLevel::Level::WARN,file,line,fmt,al);//日志输出 va_end(al);//结束可变参数列表} 可以看到里面的ERROR被错误地写成了WARN,导致输出error等级的日志时会错误输出WARN。因为这一bug涉及到项目的核心功能,所以判定为重大bug。这一重大bug导致前面的版本全都作废 数据库落地这里我们使用部署在云服务器上的MySQL数据库服务来提供远程数据库存储服务 数据库准备特别注意, ...
面向对象分析与设计(1)--软件是复杂的
复杂性complexity是软件开发避不开的问题。因为软件本质上就是复杂的,而软件开发团队的任务是制造出简单的假象(用户友好),所以软件开发者必须能够深刻认识其复杂性,并处理好复杂性问题 方法论:复杂系统的组织结构层次性一个人的能力总是有限的,复杂的系统若是没有合理的组织结构,是无法把握的,就像下图混乱组织的笔记本结构图 在上图中我们看到了有关笔记本电脑的各种相关概念,它们都是整个复杂系统的一部分,但是因为混杂在一起,彼此独立又相互有关系。但仔细观察我们可以发现,它们的关联关系并不都是等价的,因此我们按照关联关系的紧密程度,各个组成部分在系统中的地位等,将上图的概念重新组织一下 可以看到,经过多层次的组织之后。即便是复杂的笔记本结构系统,也能清晰地展示出来。而且如果我们要解释笔记本电脑的构成,也可以很自然地有了解释的顺序,比如自顶向下,笔电由软件和硬件构成,硬件又由….;在比如自底向上,我们先攒出一些列基础硬件和基础软件,然后再向上组装… 所以,对于复杂的系统,分层组织就是我们的方法论,我们的重点就是把握好每一个概念究竟是属于哪一层的,哪些概念是同一层的关系,还是上下层的关系。经过 ...
【迷你组件】MySQL登录用户管理和持久化组件
当要在代码中连接数据库时,往往需要登录用户的信息,而实际使用时登录用户常常变化,硬编码到代码中,改起来十分麻烦。所以使用Json技术将我们封装好的用户管理类序列化并储存到文件中,既能够持久化,还实现了软编码,使用户仅需方便地修改文件内容就能修改用户信息了。 用户配置类设计第三方库这里用到了两个第三方库 -ljsoncpp Json的第三方库 -lmysqlcppconn 数据库的第三方库 编译指令如下 1g++ -o $@ $^ -std=c++11 -ljsoncpp -lmysqlcppconn 代码实现作为MySQL用户配置,至少要支持储存如下信息 用户名 密码 数据库 登录ip 登录端口号 然后核心功能如下 成员变量的访问和设置 将配置写入文件 从文件读入配置 根据如上要求,我们设计的核心代码如下 DBUserConfig.hpp 12345678910111213141516171819202122232425262728293031#pragma once#include <jsoncpp/json/json.h>#include <s ...
高并发内存池--C++项目实践
项目介绍简介这是一款高并发的C++内存管理项目,原型是google的一个开源项目tcmalloc,全称Thread_Caching Malloc,即线程缓存的malloc,tcmalloc实现了高效的多线程内存管理,可以用于替代系统的内存分配的相关的函数malloc,new,free,delete等 实际上原型项目内容很多,但本着渐进学习的理念,我们可以先把tcmalloc最核心的框架简化,模拟实现出一个自己的高并发内存池。在掌握了其中的精华的设计思想和编程技巧后,我们可以再进一步实现或改造原本的tcmalloc项目,或者将学习成果用于其它项目或者更多用途 应用背景tcmalloc是一项十分常用的技术,很多对性能要求较高的场景都能用到它 高性能服务器 TCMalloc被广泛应用于高并发的服务器程序中,如Web服务器和数据库服务器。这些场景下,需要快速分配和释放内存,TCMalloc通过线程缓存机制减少了锁的竞争,提升了性能。 游戏开发 游戏引擎通常需要频繁分配和释放内存,尤其是在运行时动态创建和销毁对象。TCMalloc的低延迟和高吞吐量使其成为游戏开发的理想选择。 大数据处 ...
设计模式的C++实现(5)——原型模式
模式名称: 原型模式-Prototype类型: 创建型模式问题-使用场景: 当创建不同对象的过程过于复杂,或者需要隐藏/封装创建对象的具体过程,或者组织项目需要创建过多的子类,类的数目需要优化减少时,亦或者需要动态类时,可以由原型对象来执行类的功能解决方案: 用原型实例指定创建对象的种类,并通过拷贝这些原型来创建新的对象效果: 相比其它模式,用户只需考虑怎么检索到所需要的原型对象来拷贝出新的对象给自己用,而不用考虑如何构造。这样的设计能简化用户操作,且能极大地增加扩展性。 概念抽象原型模式旨在通过使用不同的原型对象来克隆获取不同的实例,而不是声明许多派生类,再通过派生类来实例化出不同的对象。这样减少类总数的设计方式,可以很好地简化整个项目的类的结构设计,毕竟类总数越多,要维护的类关系就越复杂,理解成本就越高。 原型模式抽象出的参与者有如下三种 Client:负责找到指定原型,并调用其克隆接口,克隆出一个对象 Prototype:抽象类,声明一个抽象接口 ConcretePrototype:实现具体的克隆操作 三者的类图关系如下: 具体使用我们来举一个具体一点的例子来 ...
【补丁更新v1.2~1.3】同步&异步⽇志系统的问题优化与异常处理
解决异步日志器黏包问题由于原本的设计是一股脑直接把日志信息送进了缓冲区,导致输出的时候会产生黏包问题。但是为什么一开始没在意呢?因为标准输出和文件输出都不在意黏包问题,同时输出多条日志是没问题的。 但是!一旦要开始插入数据库,问题就很严重了。日志信息必须一行一行储存。原本的黏包问题会导致日志信息的解析不可解,所以我们需要修改原本的代码使其能够解决黏包问题 分隔符用特定的分隔符标记一次日志的头尾是最容易想到的解决方案。 然而日志信息是字符串,任何字符都有可能出现,导致找不到特定的分隔符可以安全地分隔日志信息 分隔符只适用于待封装信息的字符在限定范围内时使用。 封装报头假如我们能获得一段日志的长度就好了。 这样的愿望可以封装报头实现。在获取一长段数据时,我们规定最前面的是报头,包含第一段报文的信息(在这个项目里只简单的包括长度信息)。这样我们就能先读取信息再读取报文了。 那么怎么标定报头的范围呢? 约定使用定长报头 约定使用分隔符 定长报头很好理解,而这里又能用分隔符了是因为报头在一段信息的最前面,最先遇到的特殊字符必定是作为分隔符存在的 这里因为没太多信息需要封装进报头,所以我们采 ...
MySQL Connector/C++常见接口/类介绍
当我们有用C++程序连接MySQL数据库并执行SQL语句时,往往要用到相关的库,这里使用的是MySQL官方提供的Connector/C++库,为了更好地使用库里的内容,我们先来熟悉一下里面常用的接口和类 MySQL准备为了便于测试,我们专门创建一个用于测试的用户和数据库,并给予相关权限 12345create user 'conn'@'localhost' identified by '12345678';create database testDB;grant all privileges on testDB.* to 'conn'@'localhost'; 认识接口/类我们将逐个介绍如下类及其相关接口 sql::SQLString sql::mysql::MySQL_Driver –<mysql_driver.h> sql::mysql::get_mysql_driver_instance() sql::Connection –<mysql ...
MySQL用户管理
为什么有用户管理类比Linux中只有root用户过于危险,因为root能随意地增删查改计算机上的任意文件 MySQL只有root用户登录也是十分危险的,因为root有增删查改所有数据库和表的权限,数据安全得不到保障,所以MySQL有自己的用户管理系统 用户管理的使用用户信息显然用户信息是需要组织和管理的,所以按照先描述,再组织的原则,我们来思考一下用户信息在逻辑上是什么样的管理思路 描述用户只需略微思考一下在MySQL中描述一个对象怎么样最方便准确,很明显,就是它自带的表结构。 实际上也确实是这样,MySQL用了一个在mysql数据库中的user表用来描述所有的用户 client1234567891011121314151617181920212223242526272829mysql> use mysqlDatabase changedmysql> select host,user,authentication_string from user;+-----------+------------------+-------------------------------- ...
设计模式的C++实现(4)——迭代器Iterator
模式名称: 迭代器-Iterator类型: 行为模式问题-使用场景: 提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示解决方案: 将对列表(对象集合)的访问和遍历从具体对象中分离出来,并放入一个迭代器对象中,由它负责实现访问和遍历功能效果: 提供了统一的遍历成员的方法,降低了用户的使用难度,提高了代码的封装性和可扩展性。代价是增加了代码复杂性,增加了更多的类,提高了代码的设计难度 注:本文的迭代器风格更偏向STL库中的迭代器,而不是《设计模式》中的抽象迭代器 灵感来源:某种意义上将,Iterator要做的事就是模仿数组中的指针,指针可以前后移动,方便地遍历数组,还可以用指针访问数组元素。我们希望把这种指针特性也用在其它数据结构上(特指组织管理多个对象的聚合体),但可惜的是原生指针的这种方便依赖于数组的地址是连续的。因此为了实现遍历和访问功能,我们需要把这些功能封装在Iterator类中,让它实例化出的对象来行使数组指针一样的行为。 类层次设计我们先来设计一个抽象迭代器类来规定迭代器应有哪些行为: 12345678910111213141516171819 ...
avatar
副驾supdriver
动物界 脊索动物门 哺乳纲 灵长目 人科 人属 智人种
我github还蛮大的
公告
主域名:
supdriver.top
网站资讯
文章数目 :
75
已运行时间 :
本站总字数 :
254.6k
本站总访问量 :
最后更新时间 :