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.mfbz.cn/a/602714.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

植被参数光学遥感反演方法(Python)及遥感与生态模型数据同化算法

原文链接&#xff1a;植被参数光学遥感反演方法(Python)及遥感与生态模型数据同化算法https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247603741&idx4&sn5b92ff13edfd6e146b7df22ac504c6d5&chksmfa8217facdf59eec9255d24b3e6f6f66b4d2814cae70f85d0ff1a…

月薪从 6k 到 30k,我做对了这3点

本文首发于公众号 极客枫哥 &#xff0c;日更分享各种好玩的软件、编程知识和个人成长故事 大家好啊&#xff5e;我是枫哥。今天跟大家聊一聊我的个人工作经历。 我是 2014 年来的上海&#xff0c;来到上海后第一份工作做的是 java 开发&#xff0c;转正后的工资是 6000。 这…

中国 Copilot 能在笔记本电脑上起飞吗?

AI PC 是 PC 的下一个进化体&#xff1f; 中国能打造出自己的 AI 研发助手吗&#xff1f; 企业如何构建 AI 竞争力&#xff1f; AI 时代&#xff0c;个体如何避免被取代&#xff1f; 如果你也有此困惑&#xff0c;那就锁定这场直播吧&#xff01; 视频号搜索【极狐GitLab】预约…

Leecode42:接雨水

第一反应是按照高低这个思路来求解&#xff0c;因为可以把盛雨水的容器想成是从左往右的&#xff0c;遇到一个沟就存一点雨水。 这个思路 看了下题解&#xff0c;发现自己的思路其实没问题&#xff0c;确实是按照最高最低来求&#xff0c;但是这个地方太复杂了求的&#xff0c…

【spark】win10 pyspark3.5.1 安装超级简单

下载地址&#xff1a;https://spark.apache.org/downloads.html 下载完成&#xff1a; 复制文件到自己的路径下&#xff0c;路径最好不要有中文、空格&#xff1b; 解压tgz文件&#xff1a; 修改环境变量&#xff1a; 创建SPARK_HOME&#xff1a; D:\software_download\spar…

STM32F103学习笔记 | 报错界面及解决方案 | 1.keil5中文注释的横竖(正与斜)问题

文章目录 一、报错界面二、解决方案参考文献 一、报错界面 二、解决方案 打开设置 在打开的设置选项卡中&#xff0c;图中Font显示的是这个软件当前设置的字体&#xff0c;可以看到字体是仿宋&#xff0c;这就是问题出现的原因&#xff0c;将之改成没有的字体就行了。 可以看…

黑马点评项目总结

登录 基于session登录 短信验证码登录 配置登录拦截器 向 Spring MVC 框架中添加拦截器&#xff0c;LoginInterceptor 是一个自定义的拦截器&#xff0c;用于拦截用户的登录请求。 excludePathPatterns这一句是设置拦截器需要放行的请求路径列表。 "/user/code", …

【Linux】常用基本指令

目录 食用说明 用户管理 whoami/who clear tree 目录结构和路径 pwd ls 文件 隐藏文件 常用选项 cd 家目录、根目录、绝对路径和相对路径 touch 常用选项 mkdir rmdir/rm man cp mv cat nano echo 输出重定向 > 输入重定向 < more/less head/…

选修选课|基于Springboot+vue的大学生选修选课系统的设计与实现(源码+数据库+文档)

大学生选修选课系统 目录 基于Springboot&#xff0b;vue的大学生选修选课系统设计与实现 一、前言 二、系统设计 三、系统功能设计 1用户信息管理 2 课程信息管理 3排课信息管理 4公告信息管理 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题…

【数据库原理及应用】期末复习汇总高校期末真题试卷06

试卷 一、选择题 1&#xff0e; ________是长期存储在计算机内的有组织,可共享的数据集合. A.数据库管理系统 B.数据库系统 C.数据库 D.文件组织 1&#xff0e; 有12个实体类型&#xff0c;并且它们之间存在15个不同的二元联系&#xff0c;其中4个是1:1联系类型&#xff0c;5…

二、双fifo流水线操作——verilog练习与设计

文章目录 一、案例分析二、fifo_ctrl模块设计2.1 波形设计&#xff1a;2.2 代码实现2.2.1 fifo_ctrl2.2.2 顶层文件top_fifo_ctrl&#xff08;rx和tx模块省略&#xff09;2.2.3 仿真文件tb_fifo_ctrl 2.3波形仿真 一、案例分析 案例要求&#xff1a;写一个 fifo 控制器&#x…

直播产品实习生实习体验报告,笔灵AI生成模版分享

实习体验报告&#xff1a;直播产品实习生 如果有不同的岗位需要写的话可以去笔灵生成一下 网址&#xff1a;https://ibiling.cn/scene/inex?fromcsdnsx 一、实习背景我是XXX&#xff0c;作为一名直播产品实习生&#xff0c;我在XX公司进行了为期X个月的实习。在这段时间里&…

Bumblebee X系列用于高精度机器人应用的新型立体视觉产品

Bumblebee X是最新的GigE驱动立体成像解决方案&#xff0c;为机器人引导和拾取应用带来高精度和低延迟。 近日&#xff0c;51camera的合作伙伴Teledyne FLIR IIS推出一款用于高精度机器人应用的新型立体视觉产品Bumblebee X系列。 Bumblebee X产品图 BumblebeeX系列&#xff…

使用C++ __builtin_expect优化程序性能后,程序体积不改变原因

结论 使用__builtin_expect优化程序性能&#xff0c;开启-O3的情况下&#xff0c;确实程序的体积可能不改变&#xff0c;但是还是会产生优化效果。 测试代码 不使用__builtin_expect #include <iostream>void fun(int a, int b) {// 不使用__builtin_expectif (a <…

poisson分布及其stata实现

1. 概念 泊松回归&#xff08;Poisson regression&#xff09;是用来为计数资料和列联表建模的一种回归分析。泊松回归假设反应变量Y是泊松分布&#xff0c;并假设它期望值的对数可被未知参数的线性组合建模。泊松回归模型有时&#xff08;特别是当用作列联表模型时&#xff0…

libcity笔记:详细流程(以DeepMove为例)

0 前置操作 这边我选择了gowalla的前1000条数据做例子&#xff1a; 0.1 生成样例dyna import pandas as pd geopd.read_csv(/home_nfs/liushuai/Bigscity-LibCity/raw_data/gowalla_test/gowalla.dyna)geo_tstgeo.iloc[:1000,:] geo_tst geo_tst.to_csv(/home_nfs/liushuai/…

电脑小工具总结(下载哔哩哔哩视频等)

哔哩哔哩视频下载器 https://www.jijidown.com/

HFSS-day3-HFSS的工作界面

工作界面也称为用户界面&#xff0c;是HFSS软件使用者的工作环境:了解、熟悉这个工作环境是掌握HFSS软件使用的第一步 HFSS工作环境介绍 1.HFSS工作界面简单的组成说明2.工作界面中各个工作窗口功能主菜单工具栏项目管理窗口属性窗口信息管理窗口进程窗口三维模型窗口 3.HFSS主…

【ITK配准】第七期 尺度(Metric)- 均方Metric

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ:870202403 公众号:VTK忠粉 前言 本文分享ITK中的均方Metric,即itk::MeanSquaresImageToImageMetricv4,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步! 你的点赞就是我的动力…

学完 C++ 基本语法后,您就可以开始学习 Qt 了。

在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「Qt的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;这些基本语法包括变量、类型、循环、判断、指针…
最新文章