C++实现自定义对象支持Range-based循环语法

目录

1.传统for循环

2.新for循环

3.实现自定义对象支持Range-based循环语法

4.总结


1.传统for循环

使用for循环的对象都是容器,如std::vector、std::list、数组、std::initializer_list、std::array等,一般遍历容器的方式有两种,一种是使用直接下标访问元素的方式,如:

int a[5] = {10, 44, 55, 2, 8};
for (int i = 0; i < sizeof(a)/sizeof(a[0]); i++){a[1] = 0;//省略其它操作
}

二是使用迭代器的方式间接访问元素,如:

int a[5] = {10, 44, 55, 2, 8};
for (auto p = std::begin(a); p != std::end(a); p++){*p = 100;//省略其它操作
}

使用auto推导出p为int*。

2.新for循环

C++11引入了基于range-based for循环语法糖,它提供了一种简洁而直观的方式来遍历一个序列或容器中的元素。它的基本语法如下:

for(decl : coll){//statement}

①decl用于声明元素及类型,如int elem或auto elem(让编译器自动推导集合中元素的类型),但应注意auto& elem和auto elem的区别,前者是元素的引用,后者是元素的副本。
②coll为元素的集合

下面是一个简单的示例代码,用于展示如何使用range-based for循环:

#include <iostream>
#include <vector>int main() {int v[] = {1, 2, 3, 4, 5};for (int i : v) {std::cout << i << " ";}std::cout << std::endl;return 0;
}

在这个示例中,我们定义了一个包含整数的数组,然后使用range-based for循环遍历其中的元素。for循环中的int i是一个迭代变量,每次循环时都会被设置为数组中的下一个元素,直到遍历完整个数组。

与传统的for循环相比,range-based for循环具有以下优点:

1)更加简洁和直观,代码可读性更高。

2)遍历序列时无需手动计数或指定迭代器,减少了出错的可能性。

3)可以用于所有支持迭代器的容器和序列,包括数组、vector、list、set、map等等。

使用注意:

(1) auto会引用元素的拷贝,有时为了效率可以考虑使用auto&或const auto&

(2) decl中要求元素的类型支持隐式类型转换。如:

const MyString& elem : vecString;(其中的vecString(类型为vector<string>)中元素的类型为string,而elem被声明为MyString,两者的类型是不同的,这会进行隐式转换,这就要求MyString类不能像explicit MyString(string);这样声明构造函数。

(3) auto自动推导出的元素类型就是容器中的value_type,而不是迭代器的类型。

(4) 不论基于范围的for循环迭代了多少次,冒号后面的表达式只会被执行一次。

(5) 基于范围的for循环和普通for循环一样,在迭代时修改容器(增加或删除元素)可能会引起迭代器失效

(6) for循环的使用还受容器本身的一些约束,如std::set<int>中的内部元素是只读的。但使用auto&时,会被推导为const auto&

3.实现自定义对象支持Range-based循环语法

自定义类支持range-base for需要满足的条件:

1)类中需要定义容器相关的迭代器(这里的迭代器是广义的,指针也属于该范畴)

2)类中要有begin()和end()的成员方法,返回值为迭代器(或重载全局的begin()和end()也可以)

//返回第一个迭代子的位置
Iterator begin()
//返回最后一个迭代子的下一个位置
Iterator end()

3)迭代器必须支持!=、*解引用、前置++等操作

  • operator++(自增),可以在自增之后返回下一个迭代子的位置
  • operator!= (判不等)
  • operator* (解引用)

下面就来举例说明怎么实现自定义对象支持Range-based循环语法

示例1:

#include <iostream>
using namespace std;
template<typename T,size_t N>
class A
{
public:A(){for (size_t i =0 ;i<N;++i){m_elements[i] = i;}}~A(){}T* begin(){return m_elements + 0;}T* end(){return m_elements + N;}
private:T m_elements[N];
};
int main()
{A<int, 10> a;for (auto iter: a){std::cout << iter << endl;}
}

输出: 0 1 2 3 4 5 6 7 8 9 

注意:在以上代码中,迭代子Iterator是T*, 是指针类型,本身就支持operator++和operator!=操作,所以这里并没有提供这两个方法的实现。

示例2:

下面是一个简单的示例,展示了如何为一个自定义的整数范围类实现基于范围的for循环:

#include <iostream>  // 自定义迭代器类  
class IntegerIterator {  
public:  using iterator_category = std::forward_iterator_tag;  using difference_type = std::ptrdiff_t;  using value_type = int;  using pointer = int*;  using reference = int&;  IntegerIterator(int value) : current(value) {}  // 前缀递增  IntegerIterator& operator++() {  ++current;  return *this;  }  // 后缀递增(不常用,但为了满足迭代器的概念)  IntegerIterator operator++(int) {  IntegerIterator tmp = *this;  ++(*this);  return tmp;  }  // 解引用  int operator*() const {  return current;  }  // 相等比较  bool operator==(const IntegerIterator& other) const {  return current == other.current;  }  // 不相等比较  bool operator!=(const IntegerIterator& other) const {  return !(*this == other);  }  private:  int current;  
};  // 自定义整数范围类  
class IntegerRange {  
public:  IntegerRange(int start, int end) : start_(start), end_(end) {}  // 提供begin迭代器  IntegerIterator begin() const {  return IntegerIterator(start_);  }  // 提供end迭代器  IntegerIterator end() const {  return IntegerIterator(end_);  }  private:  int start_;  int end_;  
};  int main() {  IntegerRange range(1, 5);  // 使用range-based for循环遍历range  for (int num : range) {  std::cout << num << ' ';  }  std::cout << '\n';  return 0;  
}

        注意,这个示例中的IntegerIterator是一个简单的迭代器实现,只支持前向迭代(即std::forward_iterator_tag)。在实际应用中,你可能需要根据你的具体需求实现不同类型的迭代器,比如双向迭代器(std::bidirectional_iterator_tag)或随机访问迭代器(std::random_access_iterator_tag)。
        另外,请注意,end()返回的迭代器应该指向范围“之后”的位置,而不是最后一个元素本身。这意味着在上面的例子中,end()返回的迭代器对应的current值是5,但实际上我们不会解引用这个迭代器来获取值。

4.总结

C++ 中为自定义对象实现基于范围的 for 循环(range-based for loop)具有多个优点,这些优点不仅使代码更加简洁和易读,还提高了代码的可维护性和灵活性。以下是一些主要的优点:

代码简洁易读:使用基于范围的 for 循环可以显著减少编写迭代循环所需的代码量。与传统的迭代器或指针循环相比,基于范围的 for 循环语法更加简洁,易于理解和编写。基于范围的 for 循环提供了更直观的方式来遍历容器或集合中的元素。它隐藏了迭代器的细节,使得循环的意图更加清晰,易于其他开发人员理解。基于范围的 for 循环是现代 C++ 编程风格的一部分,它与其他现代 C++ 特性(如 lambda 表达式、智能指针和算法库)一起使用,可以使代码更加简洁、高效和易于维护

减少错误:由于基于范围的 for 循环隐藏了迭代器的管理(如初始化、递增和检查结束条件),因此减少了与迭代器相关的常见错误,如迭代器越界或未正确初始化。

适用于多种容器:一旦为自定义对象实现了 begin() 和 end() 成员函数(或全局函数),就可以使用基于范围的 for 循环来遍历该对象,而无需修改循环的语法。这使得代码更加灵活,可以轻松地与不同的容器或集合类型一起使用。

可维护性:当需要更改遍历容器或集合的方式时(例如,从正向遍历更改为反向遍历),只需修改 begin() 和 end() 函数的实现即可,而无需更改基于范围的 for 循环的语法。这有助于提高代码的可维护性。

支持泛型编程:基于范围的 for 循环可以与模板和泛型编程一起使用,使得代码更加灵活和可重用。通过为不同类型的容器或集合提供统一的迭代接口,可以编写更加通用的代码。

        需要注意的是,range-based for循环只适用于遍历序列和容器中的元素,不能用于迭代器本身。此外,如果需要对容器中的元素进行修改,应该使用引用或指针来避免复制。

        总之,为自定义对象实现基于范围的 for 循环可以提高代码的质量、可读性和可维护性,同时减少错误并提高开发效率。这是现代 C++ 编程中值得推荐的一种做法。

参考:基于范围的 for 循环 (C++11 起) - cppreference.com

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

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

相关文章

带你快速掌握Spring Task

Spring Task ⭐Spring Task 是Spirng框架提供的任务调度工具&#xff0c;可以按照约定的时间自动执行某个代码逻辑 &#x1f4cc;一款定时任务框架 应用场景 信用卡信息银行贷款信息火车票信息 只要是需要定时处理的场景都可以使用Spring Task 只要有定时&#xff0c;就会有…

用js代码实现贪吃蛇小游戏

js已经学了大部分了&#xff0c;现在就利用我所学的js知识试试做贪吃蛇小游戏吧 以下部分相关图片以及思路笔记均出自渡一陈老师的视频 首先制作简单的静态页面&#xff0c;添加贪吃蛇移动的背景和相关图片&#xff0c;比如开始游戏等等 将各个功能均封装在函数中&#xff0…

搜维尔科技:动作捕捉解决方案:销售、服务、培训和支持

动作捕捉解决方案&#xff1a;销售、服务、培训和支持 搜维尔科技&#xff1a;动作捕捉解决方案&#xff1a;销售、服务、培训和支持l

react【实用教程】 搭建开发环境(2024版)Vite+React (官方推荐)

以项目名 reactDemo为例 1. 下载脚手架 在目标文件夹中打开命令行 npm create vite2. 安装项目依赖 cd reactDemo npm i若安装失败&#xff0c;则修改下载源重试 npm config set registry https://registry.npmmirror.com3. 启动项目 npm run dev4. 预览项目 浏览器访问 http…

iPhone 数据恢复软件 – 恢复丢失的 iPhone 数据

恢复丢失的 iPhone 数据&#xff0c;奇客数据恢复iPhone版。如今的 iPhone 用户在他们的设备上存储了大量数据&#xff0c;从照片和与亲人的文本对话到商业和医疗信息。其中一些是保密的&#xff1b;其中大部分内容都是非常个人化的&#xff1b;而且大多数一旦丢失就无法替代。…

vmware虚拟机内删除文件后宿主机空间不释放

问题描述 linux下&#xff0c;vmware内虚拟机删除文件&#xff0c;宿主机空间不释放&#xff0c;D盘快满了 解决方法 通过vmware-toolbox进行空间回收 安装 在虚拟机内操作 yum install -y open-vm-tools 清理 在虚拟机内操作 #查看磁盘的挂载点 sudo /usr/bin/vmware…

Agent AI智能体:塑造未来社会的智慧力量

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 &#x1f916; Agent AI智能体&#xff1a;塑造未来社会的智慧力量&#x1f3af; 引言&#x1f331; 智能体的未来角色预览&#x1f4bc; 行业革新者&#x1f31f; 创意合作者&#x1f6e1;️ 公共安全与环保&#x1f680; …

鸿蒙 Next 模拟器 体验

参加华为社区相关Next 的活动&#xff0c;只要申请通过就可以下载模拟器。整个过程稍微慢些&#xff0c;大家可以根据活动相关信息&#xff0c;加入微信群。跟踪催促进度。争取早日体验 next 。 目前模拟器里边还是空空的&#xff0c;没有什么内置 APP &#xff0c;但是足够大…

FTP-自用

一、登录 1、ftp服务器搭建 liunx&#xff1a;FTP服务器的搭建&#xff08;Linux&#xff09;_linux搭建ftp服务器-CSDN博客windows&#xff1a;搭建FTP服务器_ftp服务器搭建-CSDN博客 2、连接ftp服务器 ftp ip地址ftp 域名 注&#xff1a;长时间不操作自动退出 二、常用命…

php回车变br、php显示br

在 PHP 中&#xff0c;如果你想将回车符&#xff08;\n&#xff09;转换为 HTML 的 <br> 标签来实现换行显示&#xff0c;可以使用内置函数 nl2br()。这个函数会将文本中的换行符替换为 <br> 标签。以下是使用 nl2br() 函数的示例代码&#xff1a; <?php $tex…

重生奇迹MU获取宝石方法

1、商城&#xff1a;商场分为钻石商城和绑钻商城&#xff0c;钻石是直接充值的&#xff0c;绑钻是系统赠送的&#xff0c;两个地方所出售的道具都不一样&#xff0c;绑钻不能在钻石商城中购买。钻石商城中有各个等级的宝石出售&#xff0c;越高级的钻石越贵&#xff0c;不建议平…

AI换脸原理(3)——人脸对齐介绍

人脸对齐简介 人脸对齐其实包含两个步骤:人脸关键点检测、人脸对齐,英文术语有facial landmark和face alignment,主要用于精确标识眉毛、眼睛、鼻子、嘴巴以及人脸轮廓等特征部位。不同数据集对于关键点的数量有不同的设定,最少的是标记5个关键点,通常包括两只眼睛的瞳孔…

Python 中 “yield“ 的不同行为

在我们使用Python编译过程中&#xff0c;yield 关键字用于定义生成器函数&#xff0c;它的作用是将函数变成一个生成器&#xff0c;可以迭代产生值。yield 的行为在不同的情况下会有不同的效果和用途。 1、问题背景 在 Python 中&#xff0c;“yield” 是一种生成器&#xff0…

css--控制滚动条的显示位置

各种学习后的知识点整理归纳&#xff0c;非原创&#xff01; ① direction属性 滚动条在左侧显示② transform:scaleY() 滚动条在上侧显示 正常的滚动条会在内容超出规定的范围后在区域右侧和下侧显示在有些不正常的需求下会希望滚动条在上侧和左侧显示自己没有想到好的解决方案…

美国硅谷裸机云大宽带服务器在哪些行业中应用最广泛?

美国硅谷裸机云大宽带服务器在视频流媒体、实时数据分析和金融交易等行业中应用最广泛。关于美国硅谷裸机云大带宽服务器的各行业应用&#xff0c;rak部落小编为您做出详细的阐述。 美国硅谷裸机云大宽带服务器因其结合了高性能物理服务器和大带宽网络连接的特点&#xff0c;成…

【影片欣赏】【指环王】【魔戒:双塔奇谋 The Lord of the Rings: The Two Towers】

2003年发行&#xff0c;Special Extended DVD Edition Part One 1. The Foundations of Stone 2. Elven Rope 3. The Taming of Smeagol 4. The Uruk-hai 5. The Three Hunters 6. The Burning of the Westfold 7. Massacre at the Fords of Isen 8. The Banishment of Eomer …

页面嵌套,界面套娃,除了用iframe,还有其他方式吗?

UIOTOS可以了解下&#xff0c;uiotos.net&#xff0c;通过连线来代替脚本逻辑开发&#xff0c;复杂的交互界面&#xff0c;通过页面嵌套轻松解决&#xff0c;是个很新颖的思路&#xff0c;前端零代码&#xff01; 蓝图连线尤其是独创的页面嵌套和属性继承技术&#xff0c;好家…

上海亚商投顾:沪指窄幅震荡 两市成交额跌破万亿

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 沪指昨日缩量震荡&#xff0c;深成指、创业板指小幅调整&#xff0c;黄白二线分化明显。合成生物概念反复活跃…

【数据结构】基于顺序表实现通讯录

世界会向那些有目标和远见的人让路。&#x1f493;&#x1f493;&#x1f493; 目录 •&#x1f319;说在前面 &#x1f34b;基于顺序表的通讯录 • &#x1f330;1.技术要点 • &#x1f330;2.通讯录流程设计 &#x1f34b;通讯录基本量设计 • &#x1f330;1.定义联系…

AI人工智能讲师大模型培训讲师叶梓:人工智能技术引领智能搜索服务的革新

随着人工智能技术的不断进步&#xff0c;尤其是大型语言模型&#xff08;LLM&#xff09;的兴起&#xff0c;智能搜索服务的平台正面临着前所未有的革新机遇。这些平台&#xff0c;原本专注于提供知识图谱和智能搜索服务&#xff0c;现在正积极探索如何利用AI技术来优化和扩展他…