C++基础——对于C语言缺点的补充(2)

       上篇文章中说到,为了解决C语言会出现人为定义的函数和库函数出现重定义的错误,C++引入了一个新的概念,即命名空间,通过认为定义命名空间,来解决上述问题。

       在本篇文章中,将继续介绍C++相对于C语言不足来进行的补充,例如:缺省参数,重载函数等等。

1. 缺省参数:

1.1 缺省参数的定义以及单个缺省参数简单应用:

       缺省参数的定义大致如下:缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。例如下面的函数:

void PRINT(int a = 0)
{cout << a << endl;
}int main()
{PRINT(0);PRINT(10);return 0;
}

       不难发现,相比C语言中的函数书写方法,C++中,对于函数的形式参数给定了一个初始值0,该值就是上面定义中所说的缺省值。对于这种带有缺省值的函数,其调用结果如下:

       这也证实了定义中的一句话,如果没有对函数的实参进行指定赋值,则在函数执行时默认采用形参,反之采用实参。

1.2 多个缺省参数的应用:

       在上面的情况中,函数只有单一的缺省值。当函数的缺省值数量大于1时,函数的调用方式会更加多样,例如:

void PRINT(int a = 10, int b = 20, int c = 30)
{cout << a << endl;cout << b << endl;cout << c << endl;
}int main()
{PRINT();PRINT(1);PRINT(1, 2);PRINT(1, 2, 3);return 0;
}

 运行结果为:

       通过上面的例子可以看到,针对这种缺省值数量大于1的情况下,函数的调用会因为实参的给定而给出不用的效果。

       但是对于实参数值的给定,需要注意,实参的给定必须是连续的,中间不能有跳跃的情况,例如:

PRINT(, 2, );

1.3 全缺省与半缺省:

      全缺省参数就是上一部分的代码所展示,即所有的形参都给定了缺省值。对于半缺省,则是对于形式参数,不全部给定缺省值,例如:

void PRINT(int a, int b = 20, int c = 30)

但是对于半缺省参数的给定需要注意以下两点:

1. 缺省值必须从右向左给定,且必须是连续的。

2. 当函数的定义和声明分离时,缺省参数不能同时在声明和定义中出现。一般是将缺省参数给定到函数声明中

2. 函数重载:

2.1 函数重载的定义及类型:

       函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。例如下面给出的例子:

int ADD(int num1, int num2)
{cout << "int ADD(int num1, int num2) = ";return num1 + num2;
}double ADD(double num1, double num2)
{cout << " double ADD(double num1, double num2) = ";return num1 + num2;
}
int main()
{cout << ADD(1, 2) << endl;cout << ADD(1.1, 2.2) << endl;
}

       在上述代码中,建立两个函数,且这两个函数函数名相同,都是ADD,但是这两个函数的返回值类型,以及参数类型都不同,此时符合上方函数重载的定义,构成了函数重载。

      对于上述代码,运行结果如下:

         

       上面的例子展示了函数的类型不同,以及其参数类型不同的情况下可以构成重载。当函数的参数数量不同时,即:

void fun()
{cout << "fun()" << endl;
}void fun(int a)
{cout << "fun(a)" << endl;
}
int main()
{fun();fun(1);
}

      此时符合重载定义中参数数量不同这一特性,程序依旧可以正常运行,运行结果如下:

    但是上述函数有一种特殊情况需要注意,即:将函数的参数给定一个缺省值,例如:

void fun()
{cout << "fun()" << endl;
}void fun(int a = 0)
{cout << "fun(a)" << endl;
}
int main()
{fun();fun(1);
}

      运行程序,编译器会报错。这是因为在存在一个不含参数的函数与另一个有参数,且参数有缺省值的情况下,同时运行两个函数会造成二义性,即:编译器不能判断在main函数中,调用函数时,调用的函数是上面两个函数哪一个函数。

    对于函数重载,还有一种方式,即类型的顺序不同,具体情况如下方代码所示:

void fun(int a, char b)
{cout << "void fun(int a, char b)" << endl;
}void fun(char a, int b)
{cout << "void fun(char a, int b)" << endl;
}
int main()
{fun(2, 1.1);fun(2.2, 1);return 0;
}

3. 引用:

3.1 引用的概念以及基本使用:

       在C++中,引用是基于C语言中指针的不足,为解决这些不足创建的。引用的概念如下:引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。

      对应代码如下:

int main()
{int a = 1;int& c = a;
}

     main函数中,第一行代码创建了一个名为a的整型变量,第二行则是引用,即给已有的整型变量a取了一个别名叫做c

     在上面的概念中提到,编译器不会为引用变量开辟内存空间,引用与其引用的变量共用一块内存空间。因此,加入对引用进行更改,相应的变量也会更改,例如对于下面代码:

int main()
{int a = 1;int& c = a;cout << "更改前 a=" << a << endl;cout << "更改前 c=" << c << endl;c++;cout << "更改后 a=" << a << endl;cout << "更改后 c=" << c << endl;return 0;
}

运行结果为:

引用不光可以用在已有的变量上,也可以对引用进行引用,即:

int main()
{int a = 1;int& c = a;int& e = c;cout << "a = " << a << endl;cout << "c=" << c << endl;cout << "e=" << e << endl;return 0;
}

 运行结果为:

        对于引用而言,其最大的价值适用于做参数,例如在之前文章中提到到交换函数:

void Swap(int* a, int* b)
{int tmp = *a;*a = *b;*b = tmp;
}
int main()
{int x = 5;int y = 1;Swap(&x, &y);printf("%d %d", x, y);return 0;
}

        由于函数形参只是实参的一份临时拷贝,形参的改变并不会影响实参,所以在传递参数时,需要传递变量的地址。

        如果利用引用的特性,即:引用的改变会引起变量的改变,来实现交换函数,则可以一定程度上化简上述函数,即:
 

void Swap(int& a, int& b)
{int tmp = a;a = b;b = tmp;
}
int main()
{int x = 5;int y = 1;Swap(x, y);printf("%d %d", x, y);return 0;
}

      运行结果如下:

3.1 使用引用的注意事项: 

3.1.1 引用与初始化:

       在指针这部分中,如果一个指针只是被创建但是不被初始化,则这个指针称为野指针。不过指针的初始化并不是必然的,但是对于引用来说,必须被初始化,例如:

int main()
{int a = 0;int& b;return 0;
}

由于引用没有被初始化,因此程序错误。

3.1.2 引用能不能被改变指向:

        在数据结构关于的链表的文章中,如果需要在链表中插入一个新的结点,需要改变链表中指针的指向,但是对于引用而言,不能被改变指向,例如:

int main()
{int a = 0;int& b = a;int c = 1;printf("%p %p %p", &a, &b, &c);printf("\n");b = c;cout << "a = " << a << "b = " << b << "c = " << c << endl;printf("%p %p %p", &a, &b, &c);return 0;
}

运行结果如下:


       通过结果不难发现,在执行了b=c这一条代码后,b的地址依旧与a的地址相同,说明没有改变其指向。只是改变了a,b的值。

      因此,引用虽然在一定程度上弥补了指针的不足,但是由于引用并不能改变指向,因此引用并不能完全替代指针。

3.2 引用返回:

3.2.1 引用返回的概念:

在解释本节标题的内容之前,首先需要了解一个概念:

int fun()
{int n = 0;n++;return n;
}
int main()
{int ret = fun();return 0;
}

       图中给定的程序的函数的返回值返回n,在函数外部创建了一个名为ret的变量来接收函数返回值,但是,由于在函数fun运行结束后,该函数对应的栈帧全部销毁,因此,ret并不是直接接收函数的返回值,而是返回值先被存到寄存器中,ret通过寄存器来间接接收这个值。

      此时,如果将函数返回的返回值改为下方代码所示,即:

int& fun()
{int n = 0;n++;return n;
}
int main()
{int ret = fun();return 0;
}

此时再去运行程序,编译器会给出警告。这是因为在这种返回类型下,返回值并不能确定,如果编译器在函数结束后直接清理掉栈帧,则返回空,如果编译器在函数结束后,并不会立即清理掉栈帧,则返回还能有返回值。

(注:由于VS并不会立刻清理掉栈帧,因此运行该程序,返回值会返回1

       通过上面的例子,可以得出一个结论,即:在函数运行结束后,即离开函数的作用域后,此时的返回对象被销毁,因此不能采用引用返回。

但是,对于静态变量和利用malloc类似方式创建的变量,在函数结束后不会销毁,可以采用引用返回。

3.2.2 引用返回的价值:

       由于用返回的价值主要体现在C++的后续内容,因此,本文在此部分指给出结论,原理会在后续的文章中进行阐述。

1. 提高返回速度  

2. 可以修改返回对象

3.3 常引用:

对于常引用,具体可以有下面代码反应:

int main()
{const int a = 1;int& b = a;return 0;
}

        从上面代码可以看到,变量a是一个被const修饰的常变量,下面对变量a进行了一次引用。当去运行上述代码时,编译器会显示错误。

      但是如果将上述代码进行修改,即:

int main()
{const int a = 1;const int& b = a;return 0;
}

       运行此代码时,并没有错误,不难观察到,上下的给的代码唯一的差距就是第二次给出的代码的引用前加了const。因此,在进行常引用的过程中,一定不能涉及变量权限的放大。例如上面运行失败的代码中,原本变量a的权限是不能修改,但是在引用后,由于引用的修改会引起原变量的修改,因此,引用的权限超过了原变量的权限,造成了权限放大。所以导致运行错误。这里需要注意的时,只是不能放大变量的权限,对于变量权限的平移的缩小均无影响,例如:
 

int main()
{int c = 2;const int& d = c;return 0;
}

      上述代码在引用后,缩小了变量的权限,可以正常运行。

      另外,对于一个常量进行常饮用也是允许的,即:

const int& e = 10;

令外,当引用与被引用的对象存在类型转换的情况时,即:

int j = 10;double h = 15;const double& k = j;

由于类型转化的过程中,会额外生成一个常量作用于该过程,引用时k接收的值并不是i,而是i通过一个常量完成类型转换间接传给k,由于常量的常性,因此需要加上const

4. 指针与引用的练习与区别:

     1. 引用概念上定义一个变量的别名,指针存储一个变量地址。
     2. 引用在定义时必须初始化,指针没有要求
     3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何
一个同类型实体
    4. 没有NULL引用,但有NULL指针
    5. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32
位平台下占4个字节)
   6. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
   7. 有多级指针,但是没有多级引用
   8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
   9. 引用比指针使用起来相对更安全

  10.在引用这一小节开头的时候说到,引用是针对一个对象起的别名,与被引用对象共用一块空间。在汇编层上,引用是利用指针来实现的,因此也需要开辟空间。不过,在日常运用时,一般认为引用是不会开辟新空间的。

5. 内联函数:

       对于一般的函数,在函数作用时需要开辟栈帧,而内联函数不需要开辟栈帧,而是在运行中原地展开。由于内联函数不需要开辟栈帧,因此提高了程序的运行效率。

      内敛函数的书写,只需要在函数声明的开头加上inline即可,例如:

inline int Add(int x, int y)
{int z = x + y;return x + y;
}
int main()
{int x = 5;int y = 1;int ret = Add(x, y);return 0;
}

            但是需要注意,内联函数并不能完全替代普通函数,并且,当一个函数的代码函数>10行时,不建议采用内联函数。这是因为,内联函数每次调用时都会原地展开,当调用的次数较大时,例如调用10000次,则一个代码行数为50行的内联函数完全展开后为500000行,延缓程序的运行速度。

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

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

相关文章

Harbor企业级Registry基础镜像仓库的详细安装使用教程(保姆级)

Harbor Docker 官方提供的私有仓库 registry&#xff0c;用起来虽然简单 &#xff0c;但在管理的功能上存在不足。 Harbor是vmware一个用于存储和分发Docker镜像的企业级Registry服务器&#xff0c;harbor使用的是官方的docker registry(v2命名是distribution)服务去完成。 ha…

数据结构之堆的实现(图解➕源代码)

一、堆的定义 首先明确堆是一种特殊的完全二叉树&#xff0c;分为大根堆和小根堆&#xff0c;接下来我们就分别介绍一下这两种不同的堆。 1.1 大根堆&#xff08;简称&#xff1a;大堆&#xff09; 在大堆里面&#xff1a;父节点的值 ≥ 孩子节点的值 我们的兄弟节点没有限制&…

5 ip的分配

如上一节所述&#xff0c;需要和其他设备通信&#xff0c;那么需要先配置ip. 1、如何配置ip 1.可以使用 ifconfig&#xff0c;也可以使用 ip addr 2.设置好了以后&#xff0c;用这两个命令&#xff0c;将网卡 up 一下&#xff0c;就可以了 //---------------------------- 使…

AI大模型时代网络安全攻防对抗升级,瑞数信息变革“下一代应用与数据安全”

AI与大模型技术加速普及&#xff0c;安全领域也在以创新视角聚焦下一代应用安全WAAP变革&#xff0c;拓展新一代数据安全领域。近日瑞数信息重磅发布了瑞数全新API扫描器、API安全审计、数据安全检测与应急响应系统及分布式数据库备份系统四大新品。此次发布在延续瑞数信息Bot自…

freertos简单串口

先来完善一下FreeRTOSConfig.h这个配置文件 /*FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.All rights reservedVISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.This file is part of the FreeRTOS distribution.FreeRTOS is …

通信原理板块——时域均衡

微信公众号上线&#xff0c;搜索公众号小灰灰的FPGA,关注可获取相关源码&#xff0c;定期更新有关FPGA的项目以及开源项目源码&#xff0c;包括但不限于各类检测芯片驱动、低速接口驱动、高速接口驱动、数据信号处理、图像处理以及AXI总线等 1、均衡器 为了减小码间串扰的影响…

放卷开环张力控制(伺服转矩模式应用)

收放卷张力开环闭环控制算法,请参考下面文章链接: PLC张力控制(开环闭环算法分析)_RXXW_Dor的博客-CSDN博客文章浏览阅读4k次,点赞3次,收藏3次。里工业控制张力控制无处不在,也衍生出很多张力控制专用控制器,磁粉制动器等,本篇博客主要讨论PLC的张力控制相关应用和算…

Scala和Play WS库编写的爬虫程序

使用Scala和Play WS库编写的爬虫程序&#xff0c;该程序将爬取网页内容&#xff1a; import play.api.libs.ws._ import scala.concurrent.ExecutionContext.Implicits.global ​ object BaiduCrawler {def main(args: Array[String]): Unit {val url ""val proxy…

06.Oracle数据备份与恢复

Oracle数据备份与恢复 一、通过RMAN方式备份二、使用emp/imp和expdb/impdb工具进行备份和恢复三、使用Data guard进行备份与恢复 一、通过RMAN方式备份 通过 RMAN&#xff08;Oracle 数据库备份和恢复管理器&#xff09;方式备份 Oracle 数据库&#xff0c;可以使用以下步骤&a…

【微服务】mysql + elasticsearch数据双写设计与实现

目录 一、前言 二、为什么使用mysqles双写 2.1 单用mysql的问题 2.2 为什么不直接使用es 2.2.1 非关系型表达 2.2.2 不支持事务 2.2.3 多字段将造成性能低下 三、mysqles双写方案设计要点 3.1 全新设计 VS 中途调整架构 3.2 全表映射 VS 关键字段存储 3.2.1 最大程度…

FPGA高端项目:图像采集+GTP+UDP架构,高速接口以太网视频传输,提供2套工程源码加QT上位机源码和技术支持

目录 1、前言免责声明本项目特点 2、相关方案推荐我这里已有的 GT 高速接口解决方案我这里已有的以太网方案 3、设计思路框架设计框图视频源选择OV5640摄像头配置及采集动态彩条视频数据组包GTP 全网最细解读GTP 基本结构GTP 发送和接收处理流程GTP 的参考时钟GTP 发送接口GTP …

js原型链

什么叫原型链 原型链是js中的核心&#xff0c;原型链将各个属性链接起来&#xff0c;在原型链上面定义&#xff0c;原型链上的其他属性能够使用&#xff0c;原型链就是保证继承 原型链区分 原型链分为显式原型和隐式原型 显式原型&#xff1a;只有函数和构建函数才有显式原型…

spring面试题笔记

SpringBoot 有几种读取配置文件的方式 1.value 必须是bean里才能生效&#xff0c;&#xff0c;final或static无法生效 2ConfigurationProperties注解 ConfigurationProperties是springboot提供读取配置文件的一个注解 注意&#xff1a; 前缀定义了哪些外部属性将绑定到类的字…

AI:62-基于深度学习的人体CT影像肺癌的识别与分类

🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌在这个漫长的过程,中途遇到了不少问题,但是…

【漏洞复现】Fastjson_1.2.47_rce

感谢互联网提供分享知识与智慧&#xff0c;在法治的社会里&#xff0c;请遵守有关法律法规 文章目录 1.1、漏洞描述1.2、漏洞等级1.3、影响版本1.4、漏洞复现1、基础环境2、漏洞检测3、漏洞验证 1.5、深度利用1、反弹Shell 说明内容漏洞编号漏洞名称Fastjson_1.2.47_远程执行漏…

vue:js中合并对象的方法

目前比较常用的一共有三种 1、使用object.assign() 它可以将一个或多个对象的属性复制到目标对象中&#xff0c;第一个参数就是目标对象&#xff0c;这里举个例子&#xff1a; <template><div>{{data}}</div> </template> <script> export de…

劲升逻辑与安必快、鹏海运于进博会签署合作协议,助力大湾区外贸高质量发展

新中经贸与投资论坛签约现场 中国上海&#xff0c;2023 年 11 月 6 日——第六届进博会期间&#xff0c;由新加坡工商联合总会主办的新中经贸与投资论坛在上海同期举行。跨境贸易数字化领域的领导者劲升逻辑与安必快科技&#xff08;深圳&#xff09;有限公司&#xff08;简称…

Webpack的Tree Shaking。它的作用是什么?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

猫罐头怎么选?5款不踩雷的猫罐头推荐!

在我们的日常生活中&#xff0c;猫罐头是一种常见的宠物食品&#xff0c;但是有很多养猫的铲屎官都不知道应该如何为猫咪挑选一款合适且满意的猫罐头。作为经营一家宠物店7年的店长&#xff0c;我店里的猫猫最多的时候可以达到60多只&#xff0c;这些年来它们也吃过了很多种类的…

【公益案例展】中国水利水电科学研究院——云从科技青海湖湟鱼监测保护项目...

‍ 云从科技公益案例 本项目案例由云从科技投递并参与数据猿与上海大数据联盟联合推出的 #榜样的力量# 《2023中国数据智能产业最具社会责任感企业》榜单/奖项”评选。 大数据产业创新服务媒体 ——聚焦数据 改变商业 1994年青海湖裸鲤被列为国家二级保护动物&#xff0c;2003…