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

news2024/11/18 11:33:03

目录

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.coloradmin.cn/o/1692527.html

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

相关文章

计算机网络安全控制技术

1.防火墙技术 防火墙技术是近年来维护网络安全最重要的手段&#xff0c;但是防火墙不是万能的&#xff0c;需要配合其他安全措施来协同 2.加密技术 目前加密技术主要有两大类&#xff1a;对称加密和非对称加密 3.用户识别技术 核心是识别网络者是否是属于系统的合法用户 …

CSS基础(第二天)

Emmet语法 快速生成HTML结构语法 1. 生成标签 直接输入标签名 按tab键即可 比如 div 然后tab 键&#xff0c; 就可以生成 <div></div> 2. 如果想要生成多个相同标签 加上 * 就可以了 比如 div*3 就可以快速生成3个div 3. 如果有父子级关系的标签&#xff0c;可以…

进制转换【野路子改造】

非科班&#xff0c;一直都是自己的野路子&#xff0c;现在要回炉重造 十进制->二进制 基本思想&#xff1a; 开始写的&#xff08;80%&#xff09;&#xff1a; #include<stdio.h> using namespace std; int main(){ int n; scanf("%d",&n); int a[1…

Linux(Ubuntu)下MySQL5.7的安装

文章目录 1.看系统本身有没有MySQL2.安装MySQL3.登录MySQL4.修改配置文件my.cnf/mysqld.cnf5.开启远程访问功能5.1 允许其他主机通过root访问数据库5.2 Ubuntu下配置文件修改说明 1.看系统本身有没有MySQL mariadb也是mysql所以要先检查一下系统有没有MySQL 我这台机子是新机子…

FreeRTOS_任务通知_学习笔记

原文链接 任务通知 使用队列、信号量、事件组等等方法时&#xff0c;并不知道对方是谁。使用任务通知时&#xff0c;可以明确指定&#xff1a;通知哪个任务。 任务通知结构体中只有一个任务通知值&#xff0c;只能保持一个数据。 数据智能给目标任务独享。 任务通知只能一个…

win10右键没有默认打开方式的选项的处理方法

问题描述 搞了几个PDF书籍学习一下&#xff0c;不过我不想用默认的WPS打开&#xff0c;因为WPS太恶心人了&#xff0c;占用资源又高。我下载了个Sumatra PDF&#xff0c;这时候我像更改pdf文件默认的打开程序&#xff0c;发现右击没有这个选项。 问题解决 右击文件–属性–…

误差反向传播简介与实现

误差反向传播 导语计算图反向传播链式法则 反向传播结构加法节点乘法节点 实现简单层加法乘法 激活函数层实现ReLUSigmoid Affine/Softmax层实现Affine基础版批版本 Softmax-with-Loss 误差反向传播实现梯度确认总结参考文献 导语 书上在前一章介绍了随机梯度下降法进行参数与…

C语言 控制台API函数

目录 前言1. 句柄 HANDLE2. 控制台API结构体2.1 坐标结构 COORD2.2 光标信息结构 CONSOLE_CURSOR_INFO2.3 控制台屏幕缓冲区信息结构 CONSOLE_SCREEN_BUFFER_INFO 3. 控制台API函数3.1 获取句柄 GetStdHandle3.2 获取光标信息 GetConsoleCursorInfo3.3 设置光标信息SetConsoleC…

达梦8 RLOG_COMPRESS_LEVEL参数对系统的影响

测试环境是一套主备达梦数据库。下面在主备库分别设置参数进行测试 测试一、 主库设置RLOG_COMPRESS_LEVEL9&#xff0c;备库设置为0。 分别删除主备库的归档日志后执行测试脚本 #当前时间 date disql SYSDBA/SYSDBA:1807 <<EOF #显示归档大小 select sum(free)/1024…

win10无权禁用任务计划程序中的任务

问题说明 最近被win10的自动频繁更新搞得难受&#xff0c;发誓要彻底禁用这个家伙&#xff0c;于是网上找了教程执行&#xff0c;发现执行到禁用windows update计划任务时&#xff0c;提示&#xff1a; 这特么windows这个辣鸡系统&#xff0c;限制还真多&#xff01;&#xf…

❤ Vscode和Idea都可以使用的-AI插件(官方-百度出的)

❤ Vscode和Idea都可以使用的-AI插件&#xff08;官方-百度出的&#xff09; 最新AI特别火&#xff0c;给大家推荐一下最新出的VScode插件&#xff0c;辅助我们写代码&#xff01; 1、下载地址&#xff1a; > https://comate.baidu.com/zh/shopping?inviteCodefkzlak8f …

HarmonyOS-MPChart绘制一条虚实相接的曲线

本文是基于鸿蒙三方库mpchart&#xff08;OpenHarmony-SIG/ohos-MPChart&#xff09;的使用&#xff0c;自定义绘制方法&#xff0c;绘制一条虚实相接的曲线。 mpchart本身的绘制功能是不支持虚实相接的曲线的&#xff0c;要么完全是实线&#xff0c;要么完全是虚线。那么当我…

嵌入式单片机启动地址映射关系

一、内核只会从0地址启动 1.0地址第一个字是sp栈指针,第二个字是Reset_Handler入口,参考图1中启动代码中的中断向量表。具体使用流程参考图2(参考自野火) 图1 图2 2.0地址映射以后,软件上使用0地址访问的空间是映射到的器件的空间 3.0地址映射只会影响单个器件上的地址,…

【C++】09.vector

一、vector介绍和使用 1.1 vector的介绍 vector是表示可变大小数组的序列容器。就像数组一样&#xff0c;vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问&#xff0c;和数组一样高效。但是又不像数组&#xff0c;它的大小是可以动态改…

2024/5/25 英语每日一段

Alex Bols of the GuildHE group, representing 60 universities and colleges, said: “As the financial health of the higher education sector becomes ever more challenging, the need for a long-term funding solution becomes ever more urgent. “The increasing co…

鸿蒙HarmonyOS实战-Stage模型(信息传递载体Want)

&#x1f680;前言 应用中的信息传递是为了实现各种功能和交互。信息传递可以帮助用户和应用之间进行有效的沟通和交流。通过信息传递&#xff0c;应用可以向用户传递重要的消息、通知和提示&#xff0c;以提供及时的反馈和指导。同时&#xff0c;用户也可以通过信息传递向应用…

Prometheus+Grafana监控服务器、mysql数据库并配置报警规则推送邮箱

文章目录 一、安装prometheus1.1下载1.2 安装1.3 开机启动1.4 验证 二、安装 Grafana2.1 下载2.2 安装2.3 启动2.4 验证 三、安装服务器监控 node_exporter3.1 下载3.2 安装3.3 设置 node_exporter 系统服务3.4 设置开机自动启动3.5 验证3.6配置Prometheus3.7 修改 Prometheus …

海外新闻媒体发稿,PR稿件海外投稿,国外软文宣发-需综合考虑发布平台/内容质量/SEO策略/目标受众/发布时间/效果监控以及媒体关系等多个方面

发布新闻稿是提升品牌知名度和影响力的重要手段。以下是一些在国外新闻稿发布的干货分享&#xff0c;帮助你更有效地进行海外PR发稿。 1. 选择合适的发布平台 选择一个合适的新闻稿发布平台是关键&#xff0c;不同的平台有不同的覆盖范围和目标受众。以下是一些推荐的平台&am…

Java进阶学习笔记8——单继承、Object类、方法重写

Java 是单继承的&#xff0c;Java中的类不支持多继承&#xff0c;但是支持多层继承。 Object类是所有类的父类。 Java不支持多类继承&#xff1a; Java支持多层继承&#xff1a; 反证法&#xff1a; Object类&#xff1a; Object类是java所有类的祖宗类&#xff0c;我们写的任…

HCIP-Datacom-ARST自选题库__ISIS判断【23道题】

1.IS-1S快速收敛是为了提高路由的收敛速度而做的扩展特性&#xff0c;包含PRC和I-SPF&#xff0c;其中PRC只对发生变化的路由进行重新计算&#xff0c;而I-SPF只对受影响的节点进行路由计算。√ 2.在I5-S协议视图下配置ipv6 preference&#xff0c;该命令的作用是配置|5-IS协议…