C++入门:从C语言到C++的过渡(2)

目录

1.缺省参数

1.1缺省参数的概念

1.2缺省参数的分类及使用

1.3注意点

2.函数重载

2.1函数重载的定义

2.2函数重载的情况分类

2.3注意

2.4函数名修饰规则

3.引用

3.1引用的概念

3.2注意事项

3.3常引用

4.4引用的使用场景

4.4.1作为函数的参数

4.4.2做函数返回值

4.5传值和传引用

4.6引用和指针的联系与区别


1.缺省参数

1.1缺省参数的概念

缺省参数声明或定义函数时为函数的参数指定一个缺省值。在调用这个函数时,如果没有传入实参,则采用缺省值作为形参。

void print(int a = 0)
{cout << a << endl;
}
int main()
{print();//没有传参时,使用参数的默认值print(10);//传参时,使用指定的实参。return 0;
}

 输出结果: 0

                    10

1.2缺省参数的分类及使用

我们可以将缺省参数分为两类

  • 全缺省参数
void print(int a = 0,int b=3,int c=5)
{cout << a <<' ';cout << b <<' ';cout << c <<endl;
}

在使用上述代码中的全缺省参数的函数时,我们可以全部使用其给出的缺省参数,也可以从左到右给出实参。 

int main()
{print();print(7);return 0;
}

结果:0 3 5
           7 3 5 

  • 半缺省参数

半缺省参数必须从右向左依次给出,不可从左向右给,也不可间隔着给。

void print(int a,int b=3,int c=5)//a没有给出缺省值
{cout << a <<' ';cout << b <<' ';cout << c <<endl;
}

 

1.3注意点

在使用缺省参数时,我们不可在声明和定义中同时给出缺省参数,这是因为如果你同时给出了缺省值,编译器无法分辨你将缺省值给了谁。

因此,我们建议大家在声明函数时给出缺省值。 

另外,大家可能还有一个问题,为什么在使用采用了缺省值的函数时,实参必须从左往右给?为什么在给形参缺省值时,必须从右往左给呢?

问题1:在使用缺省参数时,我们的脑袋可以跳过第一个参数给第二个参数实参,但是编译器不是我们的脑袋,他没办法分辨,而且,再说了,换一个脑袋也不知道你想给第几个参数实参。

问题2:如果我们给形参缺省值时从左向右给,那么你在使用时给出实参,你给的是谁实参呢?是给了赋予了缺省值的参数实参,还是给了没有赋予缺省值的参数实参数呢?编译器又无法分辨了。

2.函数重载

在我们使用语言时,同一个词可能有很多个意思。

譬如背单词时一个单词有好多个意思......

我们希望也可以这样使用函数,因此,函数重载诞生了

2.1函数重载的定义

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

2.2函数重载的情况分类

  • 形参个数不同
void print(int a,int b=3,int c=5)//3个参数
{cout << a <<' ';cout << b <<' ';cout << c <<endl;
}
void print(int a, int b = 3)//两个参数
{cout << a << ' ';cout << b << ' ';
}
  • 形参类型不同
void print(int a, int b,)
{cout << a << ' ';cout << b << ' ';
}
void print(char a, char b,)
{cout << a << ' ';cout << b << ' ';
}
  • 形参类型顺序不同 
void print(int a, char b,)
{cout << a << ' ';cout << b << ' ';
}
void print(char a, int b,)
{cout << a << ' ';cout << b << ' ';
}

2.3注意

这里需要大家注意的是,缺省值不同不会构成重载,返回类型不同也不会构成重载

//返回类型不同
int Add(int a, int b)
{return a + b;
}
double Add(int a,int b)//error
{return a + b;
}
//缺省值不同
int Add(int a=1, int b=20)
{return a + b;
}
int Add(int a=1, int b=2)//error
{return a + b;
}

缺省值不同不会构成重载的原因一者是因为编译器调用时不知道调用哪个函数,二者需要大家了解函数名修饰规则

返回类型不同不会构成重载便需要大家了解函数名修饰规则了。

2.4函数名修饰规则

我们首先要知道编译与链接时就知道C/C++程序运行起来要经历的四个阶段:

预处理:头文件展开、宏替换、条件编译、去掉注释,生成 .i 的文件。.h的文件直接被展开。
编译: 语法检查(语法分析、语义分析、词法分析)、符号汇总、生成汇编代码,生成.s文件。
汇编: 把汇编代码转换为二进制机器码,形成符号表,生成.o文件。符号表里存放定义函数的地址信息。
链接: 合并目标文件、段表,符号表的合并和符号表的重定位,.o格式的目标文件合并到一起,生成.out/.exe文件。

    实际项目通常是由多个头文件和多个源文件构成,在上图中,main.c中调用了 sum.c中定义的sum函数,编译后链接前,main.c的目标文件中并没有Add的函数地址,因此sum是在sum.c中定义的,所以sum的地址在b.o中。那么应该怎么找到这个地址呢?

    链接阶段就是专门处理这种问题的,链接器在看到main.o调用了sum后,会到sumo的符号表中找sum的地址,然后链接到一起。

    在链接时,面对sum函数,链接器会使用哪个名字去找呢?这里每个编译器都有自己的函数名修饰规则。

下面我们可以看看在g++环境下编译的函数修饰规则

g++的函数修饰规则相对较简单:_Z+函数名长度+每个参数类型

因此,缺省值和返回值不同不会构成函数重载。

3.引用

3.1引用的概念

引用不是新定义一个变量,而是给已存在的变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间

打个比方:我本名叫小明,但我在CSDN上叫裤裤。小王和裤裤都是我。

其语法为:

int xiaoming = 3;
类型& 引用变量的名字 = 引用实际名;
int&        kuku     = xiaoming;

这里,我们先创建了一个叫xiaoming的变量,然后给他取了一个叫kuku的别名。而xiaoming和kuku实际上都是3.

通过打印它们的地址,我们发现它们的地址也是一样的,因此他们共用同一块内存空间。 

3.2注意事项

  • 由于引用变量和被引用的变量指向同一块空间,所以改变引用变量,被引用的变量也会改变。

这里将引用变量自增1,被引用的实体也自增了1.

  • 引用在定义时必须初始化 

  • 一个变量可以有多个引用
	int a = 3;int& ra=a;int& raa = a;
  • 一个引用一旦初始化一个实体,不可再引用别的实体。 
	int a = 3;int b = 5;int& ra=a;ra=b;//这时是赋值,而不是引用b
  • 无法引用类型不同的实体  

   

3.3常引用

可能大家对无法引用类型不同的实体有所疑惑,为什么要常量限定呢?

现在我们学习一下常引用。

先补充一个知识点:

如果权限是可读可写,那么我们可以在使用时将权限缩小为只读;

如果权限是只可读,那么我们在使用时就不可将权限扩大为可读可写。

简而言之,权限可以平移和缩小,但不可扩大。

使用const修饰的变量为常变量,常变量只可读,不可写。

我们可以通过const修饰引用让其变为常引用。这时引用变量就无法被修改了,根据我们刚刚说的有关权限的知识点,我们可以推导出这个结论:我们只能将常变量赋值给常引用(权限的平移),不能将常变量赋值给引用(权限的扩大)。

	const int a = 10;//只可读int& ra = a;//报错  权限不可扩大为可读可写const int& ra = a;//正确,权限的平移  可读->可读int& b = 10;//报错,权限不可扩大 10为可读不可写,b为可读可写const int& b = 10;//正确,权限的平移

现在我们补充一个知识点,类型不同的赋值会发生类型转换,而类型转换会产生临时变量,而临时变量具有常性,即临时变量只可读。

 因此,我们可以写出如下代码:

	double d = 12.34;int& rd = d;//报错,d类型转化产生只可读的临时变量,可读的权限不可扩大为可读可写。const int& rd = d;//不报错,权限的平移

在学习常引用时,我需要大家再清晰一点:

之所以在使用引用时需要注意权限的大小,是因为它操纵的是一块空间,我们可以在一个可读可写的空间中进行读写操作,但是我们无法在只可读的空间中进行写的操作。但是,我们却可以将只可读的空间中的内容拿出来赋值给一个可读可写的空间。  

4.4引用的使用场景

4.4.1作为函数的参数

由于引用操作的是同一块空间,因此我们可以作为函数的参数进行传递,这样可以达到传指针一样的效果。

int swap(int& a, int& b)
{int tmp = 0;tmp = a;a = b;b = tmp;
}

4.4.2做函数返回值

做函数返回值一定要注意变量的生命周期,要保证返回的变量在函数销毁时生命周期还没有结束,否则可能出现野指针的问题。 

int& Count()
{static int n = 0;n++;return n;
}

在这里可以再给大家拓展一个知识点:静态变量只能初始化一次,若出现多次初始化语句,则会在编译时跳过除第一句之外的初始化语句。 

现在给大家给出一个问题:

int& Add(int a, int b)
{int c = a + b;return c;
}
int main()
{int& ret = Add(1, 2);Add(3, 4);cout << ret << endl;return 0;
}//输出什么

答案是:7 

这是因为我们采用了引用返回的方式,而c在函数栈帧销毁时也跟着被销毁了。

而我们在第二次调用Add()函数时,会在原来第一次调用Add()函数时调用的空间上重新建立栈帧。

所以我们返回值的c就被覆盖掉了,而ret指向的是c的空间,因此ret的值也发生改变了。

因此这样的情况下我们传值返回即可,传值返回的返回值会在函数栈帧被销毁前放入寄存器。

4.5传值和传引用

以值作为参数或者返回值类型,在传参或者返回期间,函数不会直接传递实参或者将变量本身直接返回,而是拷贝实参形成形参或者返回变量的一份临时拷贝(放在寄存器)。因此用值作为参数或者返回值类型的效率会比较低。

4.6引用和指针的联系与区别

引用的底层实现和指针其实没有区别。

int main()
{int a = 10;int& ra = a;ra = 20;int* pa = &a;*pa = 20;return 0;
}

现在我们观察一下这段代码的汇编:

但引用和指针还是有一定区别的

1.引用是变量的别名,指针是变量的地址

2.引用必须初始化,指针建议初始化

3.引用初始化后不可修改对象,但指针可以

4.引用的大小为引用类型的大小,指针要看平台。

5.没有多级引用,但是有多级指针

6.引用更安全

码字不易,给裤裤一个三连关注评论叭~~

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

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

相关文章

【学习笔记】Windows GDI绘图目录

题外话 不知几时开始&#xff0c;觉得学习过程中将内容记录下来&#xff0c;有助于加强记忆&#xff0c;还方便后续查找&#xff0c;顺便帮助有需要的人&#xff0c;更有来自您阅读、点赞、收藏和评论时给我带来的动力与兴奋。 目录 【学习笔记】Windows GDI绘图(一)图形概述…

B站大数据分享视频创作300天100+原创内容4000+粉

以今年五一作为一个里程碑参考点&#xff0c;给明年一个可以比较的数据。 我正经发力创作是2023.06.17 (前面几个视频是试水)&#xff0c;300天不到一年时间 创作了100原创数据相关视频&#xff0c;创作频率应该很高了&#xff0c;收获了下面几个数字&#xff0c;审视自身&…

如何建设高效的外贸自建站?

建设高效的外贸自建站&#xff0c;首先要从明确目标和受众开始。了解你的目标市场和潜在客户是关键&#xff0c;这样你可以有针对性地进行设计和内容创作。站点的设计应该简洁明了&#xff0c;导航要方便&#xff0c;确保访客户能够快速找到所需的信息。 而内容是网站的核心。…

Java基础的语法---String

Java的String类是不可变的&#xff0c;意味着一旦创建&#xff0c;其值就不能被改变。String类提供了丰富的API来操作字符串。 以下是一些常用的方法&#xff1a; 构造方法&#xff1a; 有以下几种常见的&#xff1a; public class stringlearn {public static void main(S…

ATmega328P加硬件看门狗MAX824L看门狗

void Reversewdt(){ //硬件喂狗&#xff0c;11PIN接MAX824L芯片WDIif (digitalRead(11) HIGH) {digitalWrite(11, LOW); //低电平} else {digitalWrite(11, HIGH); //高电平 }loop增加喂狗调用 void loop() { …… Reversewdt();//喂狗 }

从0到1!得物如何打造通用大模型训练和推理平台

1.背景 近期&#xff0c;GPT大模型的发布给自然语言处理&#xff08;NLP&#xff09;领域带来了令人震撼的体验。随着这一事件的发生&#xff0c;一系列开源大模型也迅速崛起。依据一些评估机构的评估&#xff0c;这些开源模型大模型的表现也相当不错。一些大模型的评测情况可…

佩戴安全头盔监测识别摄像机

佩戴安全头盔是重要的安全措施&#xff0c;尤其在工地、建筑工程和工业生产等领域&#xff0c;安全头盔的佩戴对于工人的生命安全至关重要。为了更好地管理和监控佩戴安全头盔的情况&#xff0c;监测识别摄像机成为了一项重要的工具。监测识别摄像机可以通过智能技术监测并记录…

JavaScript-数组的增删改查

数组的操作一共有四种&#xff1a; 查询数组数据修改数组中元素的值数组添加新的数据删除数组中的元素 数组的初始化 有些编程语言的数组初始化是用{}包着的&#xff0c;而JS的数组初始化用[] let num[2,6,1,77,52,25,7]; 数组的查询 想要具体查询数组中的某个元素 可以用数…

项目9-网页聊天室7(消息传输模块之解决之前存在的问题:获取最后一条消息)

1.服务器中转的原因 IPV4不够用 &#xff08;1&#xff09;使用服务器中转,最大原因, 就是 NAT 背景下,两个内网的设备无法直接进行通信(不在同一个局域网内) &#xff08;2&#xff09;另外一个原因,通过服务器中转,是更容易在服务器这里记录历史消息随时方便咱们来查询历史记…

C语言实现Hash Map(2):Map代码实现详解

在上一节C语言实现Hash Map(1)&#xff1a;Map基础知识入门中&#xff0c;我们介绍了Map的基础概念和在C中的用法。但我写这两篇文章的目的是&#xff0c;能够在C语言中实现这样的一个数据结构&#xff0c;毕竟有时我们的项目中可能会用到Map&#xff0c;但是C语言库中并没有提…

C语言学习笔记之指针(一)

目录 什么是指针&#xff1f; 指针和指针类型 指针的类型 指针类型的意义 指针-整数 指针的解引用 指针 - 指针 指针的关系运算 野指针 什么是野指针&#xff1f; 野指针的成因 如何规避野指针&#xff1f; 二级指针 什么是指针&#xff1f; 在介绍指针之前&#…

第十五届“北斗杯”全国青少年空天科技体验与创新大赛安徽赛区阜阳市解读会议

5月19日&#xff0c;第十五届“北斗杯”全国青少年空天科技体验与创新大赛安徽赛区阜阳解读活动在阜阳市图书馆隆重举行。共青团阜阳市委员会学少部副部长丁晓龙、阜阳市师范大学物理系副主任黄银生教授、安徽科技报阜阳站站长李伟、市人工智能学会秘书长郭广泽、“北斗杯”安徽…

【开发 | 环境配置】解决 VSCode 编写 eBPF 程序找不到头文件

问题描述&#xff1a; 在使用 vscode 编写 eBPF 程序时&#xff0c;如果不做一些头文件定位的操作&#xff0c;默认情况下头文件总是带有“红色下划线”&#xff0c;并且大部分的变量不会有提示与补全。 在编写代码文件较小时&#xff08;或者功能需求小时&#xff09;并不会…

开放式耳机什么牌子好用?五大高分力作安利,不容错过!

​开放式耳机如今备受瞩目&#xff0c;其独特的不入耳设计不仅避免了长时间佩戴对耳道的压力&#xff0c;还维护了耳朵的卫生健康&#xff0c;特别受运动爱好者和耳机发烧友青睐。然而&#xff0c;市场上的开放式耳机品质良莠不齐&#xff0c;让许多消费者在选择时陷入困惑。作…

嵌入式全栈开发学习笔记---C语言笔试复习大全20

目录 指针数组 数组指针 指针和二维数组 通过指针访问二维数组 通过数组指针访问二维数组 用指针表示二维数组并访问 地址等级 0级地址&#xff1a; 一级地址&#xff1a; 二级地址&#xff1a; 三级地址&#xff1a; 总结 指针的指针 命令行参数 上一篇复习了指…

路由_传递params参数和query参数

传递params参数 传递params参数可以直接在路径后面加上参数&#xff1a; 上述就是在路径变化的时候传过去三个值分别为哈哈、嘿嘿、呵呵的参数 但是这样的话会被认为三个参数是路径的一部分&#xff0c;计算机没有办法区分哪些是路径哪些是参数&#xff0c;所以首先要在这条路…

React useState数组新增和删除项

在React中&#xff0c;我们可以使用useState钩子来管理组件的状态&#xff0c;其中包括数组。如何在React函数组件中对数组进行增加和删除项的操作&#xff1f; 新增项时&#xff1a;我们可以对原数组进行解构&#xff0c;并把新增项一起加入到新数组&#xff1b; 删除项时&…

LeetCode 264 —— 丑数 II

阅读目录 1. 题目2. 解题思路3. 代码实现 1. 题目 2. 解题思路 第一个丑数是 1 1 1&#xff0c;由于丑数的质因子只包含 2 、 3 、 5 2、3、5 2、3、5&#xff0c;所以后面的丑数肯定是前面的丑数分别乘以 2 、 3 、 5 2、3、5 2、3、5 后得到的数字。 这样&#xff0c;我…

电脑同时配置两个版本mysql数据库常见问题

1.配置时&#xff0c;要把bin中的mysql.exe和mysqld.exe 改个名字&#xff0c;不然两个版本会重复&#xff0c;当然&#xff0c;在初始化数据库的时候&#xff0c;如果时57版本的&#xff0c;就用mysql57(已经改名的)和mysqld57 代替 mysql 和 mysqld 例如 mysql -u root -p …

LLM 大模型学习必知必会系列(十):基于AgentFabric实现交互式智能体应用,Agent实战

LLM 大模型学习必知必会系列(十)&#xff1a;基于AgentFabric实现交互式智能体应用,Agent实战 0.前言 **Modelscope **是一个交互式智能体应用基于ModelScope-Agent&#xff0c;用于方便地创建针对各种现实应用量身定制智能体&#xff0c;目前已经在生产级别落地。AgentFabri…