【C++】C++中如何处理多返回值、C++中的模板

news2024/9/29 0:12:33

十四、C++中如何处理多返回值

本部分也是碎碎念,因为这些点都是很小的点,构不成一篇文章,所以本篇就是想到哪个点就写哪个点。

1、C++中如何处理多个返回值
写过python的同学都知道,当你写一个函数的返回时,那是你想返回谁就能返回谁,想返回几个就可以返回几个,几乎是非常的随心所欲了,因为python背后是做了很多很多事情才让你如此肆意的。C++就非常不行了,因为C++本身就很底层,没有更底层的东西去为它做这些事情了,所以所有都得C++自己花式变出来。

我们都知道,C++默认情况下,一个函数是不能返回两个对象的,就是只能返回一个特定的对象,所以更别提返回多个类型的对象了
那你的意思是python都能完成的事情,C++却完成不了?非也,这两者根本都没有可对比性。C++是底层,就是所有顶层的东西都是底层一生二、二生三、三生万物而呈现出来的百花齐放。底层不存何来万物。所以C++当然也可以实现返回多个对象,只是这个实现过程需要你用你的智慧去实现。

所以在C++中,你要使一个函数返回多个对象或者多种类型的对象,其实是有很多不同的方法可以实现的。下面我就尽量多罗列几种方法吧。

(1)利用结构体实现
我个人也比较推荐这种方法,比较清晰也好理解。

这里想强调的是,只要涉及到多返回值,或多或少都要涉及到复制,只要涉及到复制,性能就是一个绕不开的话题。上述例子中,两个字符串是程序进入main函数后,先开始运行func函数,而运行func函数就先组织参数,组织参数就是在常量区先写入"lyy""liyuanyuan"这两个字符串,然后才开始执行func,func又是在栈内存创建的,而执行func我们是通过引用传参的,这样就少了一次复制。
func函数执行完毕,就是赋值给e。此时就得先找到连续的空间给e,然后把e的3个对象的值初始化成func的返回值。此时必定的复制呀。所以这里想说的是不管你使用哪种方法,你脑子里一定要不断确认是否有性能问题。

(2)通过参数实现
这种方法不需要使用C++提供的特定类(方法),但是稍微有点难懂

通过参数实现一个函数多返回值的方法,稍稍难理解,不过如果你对传值、传址、指针、引用这些基础概念非常清晰的话,其实也不难。
所以这里要强调的是,如果你是通过参数实现的,那你千万可不能传值,传值将不会得到你想要的结果的。因为func函数的返回值变量,我们是先定义到main函数里,然后再把变量的引用(上左图)或者变量的地址(上右图)传给func,然后在func函数体内初始化或者修改或者赋值这些变量的。
如果你传给func是变量的值,那func会在自己体内重新复制一份数据,然后再计算,结果就和main函数中定义的变量完全无关了,所以你就得不到你想要的结果了。

(3)通过数组实现返回相同类型的多个对象
通过数组实现是最难懂的,是考察一个人对C++基本数据类型的理解程度和灵活使用程度。因为C++还兼容了底层的C,所以数组本身就非常复杂,有最基本的C风格数组、array数组、动态数组vector、还有字符串也有自己单独的数组string[],更有很多变异的交叉组合的东西,比如指针数组、数组指针、高维数组、指向数组首元素的指针、指向数组的指针、指向“指向数组的指针”的指针、函数指针、指针函数、函数返回一个指针、指针指向一个函数、用指针当参数传参、还可以和结构体、类等结合,等等,非常晦涩,非常考验你的底层基础理解得有多深入。

针对本小知识点,你要清楚下面三方面:
首先你要明确:C++中的函数是不能返回普通数组的!会报编译错误!那我们又想让函数返回一个普通数组怎么办?我们可以通过返回一个指针来曲线救国,就是要通过直接返回一个指针的方式,来间接返回一个数组。我们知道一个数组的数组名就是这个数组的第一个元素的指针,&数组名就是一个指向数组的指针。所以一是你可以返回这个数组的&数组名(下面的A案例)。二是你可以返回一个指向指针数组名的的指针,就是返回一个指向指针的指针(下面的B案例)。

其次,前面知识点牢固的同学都知道,在C++中,数组可以用C风格的、也可以用array数组。所以你用哪种类型的数组,难度是不一样的。C风格的数组几乎就是内置类型了,非常底层,所以非常难,但效率高。array数组是标准库的东西,已经包装得非常人性化了,虽然简单好用但肯定是要多一点点开销的。我们先展示如何用最原始的C风格的数组(A案例、B案例、D案例),再展示array数组(C案例)。

最后,不管我们是用C风格数组还是array数组,也不管我们是要返回指针数组的数组名还是返回一个指向指针的指针,背后都还是数组,那既然是数组,数组是要求所有元素的数据类型是相同的。即使你的数组是指针数组,也是要求所有元素(指针)指向的对象都是相同类型的。所以下面案例中就不能比如创建两个字符串数组,再创建也给整型,然后再创建一个指针数组,把三者的地址分别放进去!这样是没法赋值指针数组中的元素的!虽然每个元素都是地址,但是也是没法赋值的。所以下面的A、B、C案例我们都用的是字符串类型。就是只能返回某一个类型的多个对象,不能返回多个类型的对象。不像上面的结构体方法、参数方法是可以返回多个类型的多个对象的。

A案例:返回指向指针数组的指针

上面展示的案例中,func函数返回的是一个指向“指针数组”的指针。就是func返回了一个指针,这个指针指向的是一个数组,这个数组中的元素又都是指针,这些元素又指向堆内存中的字符串数组。但是上述案例main函数中调用func函数的做法有些不恰当。因为这种调用方式根本没有任何用处,因为一点func函数调用完毕,“指针数组”就随着func函数的结束而湮灭了,那要一个指向"指针数组"的指针干嘛用啊,一个指向不存在的指针没有任何用处的。所以main函数应该如下写法:

B案例:返回指向指针的指针

这次我在堆上创建指针数组,这样就不会出现调用func完毕后,指针数组消失的情况了(上图方法1)。或者我还可以先在main函数创建一个指针数组,然后当参数传给func,让func给我初始化一下再返回(上图方法2)。当然也可以不用返回(就是下面图D案例)。

C案例+ D案例: 
C案例中,虽然s1、s2、array都是在func函数内部创建的,main函数调用了func后,这些对象都还在,那是因为main函数又自己复制了一份数据。由于array库给我们包装了很多东西,所以这里的代码看起来就非常容易理解。
D案例也是非常巧妙的用法,和前面的小标(2)的思路是一样的。

E案例:返回vector数组

C案例中的array是在栈上创建的,vector会把它的底层存储存储在堆上,所以从技术上讲array会更快。

上面给大家展示这么多小案例,也只是一部分,聪明的你应该能想出更多的办法。这里仅仅是为了展示各种用法。用法和用法是没有优劣之分的,每种用法都有其特定的应用场景。只有非常了解每种用法才能灵活应用。此处也是深刻的领略了一下C++的超级灵活性,真是像水的品行一样,可以各种变形、各种绕开、各种组合,利万物而不争、静水深流、强大而温润。如果你对指针、数组、指针数组、数组指针等这些基础概念不清晰的同学,你就会非常懵,花式报错,建议仔细看这篇博文:【C++】深度理解C++数据类型:常量、变量、数组、字符串、指针、函数_c++ 字符串常量-CSDN博客 ,这篇博文是基础中的基础,是C++内置类型的详细说明,你把这些吃透了,这些案例你也就懂了。

(4)通过元组tuple实现多个返回对象

(5)通过Pair实现多个返回对象

十五、C++中的模板templates

本部分讨论C++中的模板templates
在别的语言中,比如java、c、c#等托管语言中,模板类似泛型的概念,但模板比泛型要强大得多。模板有点像宏,而泛型却非常受限于类型系统以及其他很多因素。同时模板也是一个巨大的、复杂的话题,本部分仅仅是浅浅的入门。

1、什么是模板
模板就是基于你给定的一套规则让编译器为你写代码。或者通俗的说就是,你写个模板,里面抠出一些空,这些空填上不同的东西,就是一个可用的对象。或者我举个例子,比如开发票,其实发票的格式都是一样的,只有抬头、金额、数量等几个要素不一样。你把空发票就可以看出模板,里面的抬头、金额、数量等几个地方是空的,你只要根据不同的客户填上不同的信息,每个客户的发票就开好了。通俗的理解,模板就是那个空发票。你把要填的信息填到对应的空里面,就你生成一张特定客户的发票了。
所以模板就是把代码的某些部分挖掉,然后传给编译器挖掉部分要填的内容,编译器就帮你完成这段代码了。所以说模板就是你给编译器一个套路,然后再给要填的空的答案,编译器就自动帮你完成了。

2、为什么要用模板

如上左图所示,我只是想写一个func函数,但是我得要允许func函数可以接受各种类型的参数,比如整型、字符串、浮点型等等,那此时我就得写好几个函数重载,如上图A处。而且这些重载函数除了参数类型不一样外,其他地方都一模一样。手动重复写A处这么多差别不大的函数太费劲。如果我写一个模板,其他都写全,就把参数类型空出来,然后我给编译器传入那个空的答案,编译器像填空一样帮我填上就行了。这样我就省力很多了。这就是template诞生的初衷。

说明:cout是可以接受任何基本类型的或者说C++内置类型,就是我们现在正在使用的这些类型。

3、template的语法
上右图B处是template的语法:template单词就表示你定义了一个模板;尖括号里面的typename是模板的参数;T是名字,你可以随便取。
T用在C处。也就是T可以在整个模板代码中使用,来代替任何出现类型的地方。比如如果代码中出现int value,我们就可以写成T value;再比如如果出现string value,我们也可以写成T value。

当你定义了一个模板后(B处),编译器就会在编译期评估这个模板。所以上右图B、C处的代码不是真正的代码,func函数也不是一个真正的函数,它只是模板的一部分。只有当我们实际调用它的时候(D处),func函数才被真正的创建,创建时也是根据我们传入的参数类型,T才被替换,func才被创建出来,并作为源代码的一部分进行编译的。所以,比如MSVC编译器就不会对你不使用的模板错误进行报错,但是比如Clang等一些编译器会报错。

4、模板的工作原理

当我们调用func("hello")时,模板的另一个版本的函数就会被编译器创造(把尖括号中的类型替换T),并复制到模板下面,然后才编译。
所以模板的工作原理就是,当你调用模板中的函数时,编译器就根据你给它的信息,把该填的空都对应填上,并将生成的代码复制到模板后面即可。

模板不仅可以让编译器帮我们写函数,还可以写类。事实上,大量的C++标准模板库同样完全使用了模板,下面我们再展示如何写类的模板:

上面右图我们创造数组的方式,和C++标准模板库创造array数组的方式一样。记不记得array数组也是让我们在尖括号里面提供两个参数,一个是数组的类型,一个是数组的长度。所以模板有点像C++的meta programming(元编程),就是编译器在编译时实际还进行了编程。

了解模板模板的工作原理后,我们自然可以判断,不是什么情况都适合使用模板的,有的个性化非常强的工作,你就还是别使用模板了。如果是一些重复性很强的工作,比如日志系统,比如要写很多类型的重载函数,这样的工作使用模板就是非常合适的。

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

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

相关文章

STM32 F1移植FATFS文件系统 USMART组件测试相关函数功能

STM32 F1移植FATFS文件系统 使用USMART调试组件测试相关函数功能 文章目录 STM32 F1移植FATFS文件系统 使用USMART调试组件测试相关函数功能前言部分主要相关代码# USMART介绍1. mf_scan_files 扫描磁盘文件2. mf_mount 挂载磁盘3. mf_open 打开文件4. mf_read 读数据内容5. mf…

软件测试学习路线图

软件测试工程师是专门从事软件、系统或产品测试和评估的技术专业人士,确保它们符合既定标准并无任何缺陷。通过精心设计和执行测试计划,软件测试工程师发现 Bug、故障和需要改进的领域,从而提高最终产品的可靠性和性能。 软件测试工程师在软…

干货|CNAS-CL01设备部分解读,透彻掌握软件测试实验室设备关键点

CNAS-CL01《检测和校准实验室能力认可准则》是软件测试实验室建立符合CNAS标准的质量管理体系必须要贯彻的一部准则,分为五大核心部分:通用要求、结构要求、资源要求、过程要求和管理体系要求。前面的文章中我们为大家分享了通用要求部分、结构要求部分以…

WebAssembly进阶,vue3 使用 WebAssembly,及 WebAssembly vs JavaScript 的性能对比

目录 核心使用步骤 .c文件.cpp文件编译 使用 Emscripten 转译文件 页面中引入.wasm文件中的函数 WebAssembly vs JavaScript 的性能对比 性能对比关键点: 具体场景 实际案例分析 如果对WebAssembly不熟悉可以前往:WebAssembly最详教程,进行WebAssembly基础学习 Web…

一篇文章弄懂数据结构中的各种排序_插入排序_冒泡排序_快速排序_堆排序_归并排序_基数排序

文章目录 一篇文章弄懂数据结构中的各种排序1.排序的概念2. 插入排序2.1 直接插入排序2.2 折半插入排序2.3 希尔排序 3.冒泡排序3.1 算法原理3.2 性能分析 4.快速排序4.1 算法原理4.2 性能分析 5. 选择排序5.1 简单选择排序5.2 堆排序5.1 算法流程5.2 算法效率分析5.3 堆排序的…

2024CSCO 芦康沙妥珠单抗创造晚期TNBC二线治疗新高度

前言 “魔法子弹”的概念从上世纪初提出,经过一百多年的不断探索,抗体药物偶联物(ADC)从理想照进现实,达到今天百舸争流的盛况,被认为是极具前景的创新疗法,全球范围内已有十余款产品被批准用于…

使用Mendeley生成APA格式参考文献

Mendeley 是一款文献管理工具,可以在Word中方便的插入引用文献。 效果对比: 注:小绿鲸有三种导出格式,分别为复制、导出为Bibtex和导出为Endnote三种。 Mendeley 下载与安装 Download Mendeley Reference Manager For Desktop m…

报道|解读INFORMS期刊影响因子的下降及运筹与管理科学出版的未来

编者按 David Simchi-Levi和Tinglong Dai老师近期在ORMS Today上发表了一篇名为拥抱影响力的变化:解读INFORMS期刊影响因子的下降及运筹与管理科学出版的未来的文章,探讨了近几年INFORMS的大多数期刊影响因子下降的原因以及带给我们的启示。 2023年7月&a…

Qt 首次配置 Qt Creator 14.01 for Python

前言: 如何用QT实现Python的配置的交互界面。本文从0开始,进行实践的介绍。 在上一节里面,我们做了社区版本的配置: https://blog.csdn.net/yellow_hill/article/details/142597007?spm1001.2014.3001.5501 这一节&#xff0…

Linux —— udp实现群聊代码

一、介绍 前面我们一步步模拟实现了一个简单的udp服务器和客户端,通过这个服务器,我们简单实现一个群聊的功能,本篇是专门用来记录代码的,详细的实现思路可以去参考我其他两篇,Socket编程(一)和…

Android性能优化相关的10个经典面试题

本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点 以下是一些Android性能优化面试问题,包括问题和参考解答: 1. 如何优化Android应用的启动速度? 答案&#…

零基础教你如何开发webman应用插件

0X07 发布插件应用 插件应用发布地址 https://www.workerman.net/app/create。填写好发布相关信息 0X08 上传源码zip文件 提交完成之后等待官方审核就可以啦! 0X09 安装插件 应用插件安装有两种方式 在插件市场安装 进入官方管理后台webman-admin 的应用插件页点击…

tauri开发配置文件和文件夹访问路径问题

文件夹没权限:Unhandled Promise Rejection: path not allowed on the configured scope: /Users/song/Library/Application Support/com.pakeplus.app/assets/default.png 没有文件夹,需要先创建:Unhandled Promise Rejection: path: /Users…

GB28181信令交互流程及Android端设备对接探讨

GB28181规范必要性 好多开发者在做比如执法记录仪、智能安全帽、智能监控等设备端视频回传技术方案选型的时候,不清楚到底是用RTSP、RTMP还是GB28181,对GB28181相对比较陌生,我们就GB28181规范的必要性,做个探讨: 实现…

vue+UEditor附件上传问题

🏆本文收录于《全栈Bug调优(实战版)》专栏,主要记录项目实战过程中所遇到的Bug或因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&am…

【软件测试】详解软件测试中的测试级别

目录 一、测试级别二、组件测试三、开发者测试3.1测试与调试3.2 组件测试目标3.3 测试功能 四、稳健性测试4.1 效率的测试4.2 测试可维护性4.3 测试策略4.4 白盒测试 一、测试级别 软件系统通常是由许多子系统组成的,而这些子系统又是由多个组件组成的,…

基于STM32的无人驾驶车辆系统

目录 引言项目背景环境准备 硬件准备软件安装与配置系统设计 系统架构关键技术代码示例 传感器数据采集与处理路径规划与避障控制实时反馈与控制系统应用场景结论 1. 引言 随着无人驾驶技术的发展,嵌入式系统在无人驾驶车辆中的应用变得越来越重要。STM32作为高效…

ECMAScript 与 JavaScript 的区别详解

ECMAScript 与 JavaScript 的区别详解 在前端开发的学习过程中,很多开发者会遇到两个常见的术语:ECMAScript 和 JavaScript。这两个术语常常被混淆,因为它们密切相关,甚至有时被认为是同一件事。本文将详细解析 ECMAScript 和 Ja…

盘点4款专业高效的数据恢复工具。

超级兔子数据恢复工具具有广泛的系统适配性,功能丰富,操作简单,是一款比较专业的数据恢复软件。如果大家在为数据丢失而烦恼的话,我可以推荐几款好用的数据恢复软件给大家。 1、福昕数据高效恢复 直通车:http://www.p…

有哪些使用的电脑安全小技巧?

以下是一些电脑使用的安全技巧: 1. 定期更新系统和软件: 操作步骤:打开系统设置中的“更新和安全”选项,启用自动更新。对于软件,在其设置中查找更新选项并定期检查。 2. 设置强密码: 操作步骤&#xf…