C++入门——缺省参数|函数重载

news2024/12/24 3:27:49

前言:

        C++入门我们主要是补充C语言的不足,为后续类和对象学习打基础。在前面我们学了命名空间、输入输出,今天我们继续学习。

上期链接:

C++入门——关键字|命名空间|输入&输出_wangjiushun的博客-CSDN博客

目录:

1. 缺省参数

2. 函数重载


一、缺省参数(也叫默认参数)

1、缺省参数概念

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

        代码演示:

#include<iostream>

using namespace std;

//在缺省参数是在声明或定义函数时为函数的参数指定一个缺省值。
//如Func函数,在定义时为形参a提供了默认实参,默认实参作为形参的初始值出现在形参列表中。
void Func(int a = 0)
{
	cout << a << endl;
}

int main()
{
	Func();//①没有传参时,使用参数的默认值
	Func(10);//②传参时,使用指定的实参
	return 0;
}

说明:

1、函数参数指定缺省值时,可以不传参(使用参数缺省值),也可以传参(使用指定的实参)。

2、函数参数没有指定缺省值时,必须传参。

2、缺省参数分类

(1)全缺省参数 —— 所有形参都提供缺省值

        代码实例:

#include<iostream>

using namespace std;

void Func(int a = 10, int b = 20, int c = 30)
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
}

int main()
{
	Func();
	Func(1);
	Func(1, 2);
	Func(1, 2, 3);
	return 0;
}

        我们参数的传递是怎么传递的呢?能跳着传吗?

        答案是:语法规定实参传实参的顺序是从左向右依次传递的。注意:不能跳着传参,因为祖师爷不喜欢(即规定是这样,祖师爷最大)。

(2)半缺省参数 —— 是形参缺省一部分,不是就说缺省一半。并且规定缺省值是从右向左依次缺省的。

        代码演示:

#include<iostream>

using namespace std;

void Func(int a, int b = 20, int c = 30)
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
}

int main()
{
	//参数的传递规定是从左向右依次传递的,不能跳着传。
	//所以标准规定缺省值是从右向左依次缺省的。
	//因为Func的第一个形参a没有缺省,所以Func的第一个参数必须传
	Func(1);
	Func(1, 2);
	Func(1, 2, 3);
	return 0;
}

(3)使用场景示例

        代码演示:栈的初始化

分析:

        ①静态的栈,给小了不够用,给大了浪费,但是效率比较高(因为不存在扩容问题)。

        ②当我们明确知道栈要插入几个数据时,传参;当我们不知道栈要插入几个数据时,那就不传参了。

        ①C语言实现:

#define DEFAULT_CAPACITY 4
void StackInit(struct Stack* pst)
{
	pst->a = (int*)malloc(sizeof(int) * DEFAULT_CAPACITY);
	if (pst->a == NULL)
	{
		perror("malloc fail:");
		return;
	}
	pst->top = 0;
	pst->capacity = DEFAULT_CAPACITY;
}

说明:

1、C语言有几个形参就必须传几个实参,一一对应。(即C语言不支持缺省参数)

2、C语言使用宏替代不灵活  ——定义不同栈的时,他们的初始化都相同。     

        ②C++实现:

#include<iostream>

using namespace std;
struct Stack
{
	int* a;
	int top;
	int capacity;
};

//初始化栈
void StackInit(struct Stack* pst,int defaultCapacity = 4)
{
	pst->a = (int*)malloc(sizeof(int) * defaultCapacity);
	if (pst->a == NULL)
	{
		perror("malloc fail:");
		return;
	}
	pst->top = 0;
	pst->capacity = defaultCapacity;
}

int main()
{
	struct Stack st1;
	//插入100个数据
	StackInit(&st1, 100);
	struct Stack st2;
	//不知道要插入多少数据
	StackInit(&st2);
	return 0;
}

说明:

1、缺省参数——①传参时,使用指定的实参;②没有传参时,使用参数的缺省值。

2、对比C语言,有了缺省参数就灵活了一些。

3、缺省参数的注意事项(易错点)

1、半缺省参数必须从右往左依次给出,不能间隔着给

2、缺省参数不能在函数声明和定义中同时出现

3、缺省值必须是常量或者全局变量

4、C语言不支持缺省参数

讲解:

        (1)缺省参数不能在函数声明和定义中同时出现

                答案是:语法规定只能一个给,不能两个同时给(就像你小时候,学校让你交资料费时,你只有向你妈或你爸要,不能两边都要,否则就要被打了)。

代码演示:

#include<iostream>

using namespace std;

void Func(int a, int b = 20, int c = 30);

int main()
{
	Func(1);
	Func(1, 2, 3);
	return 0;
}

void Func(int a, int b = 20, int c = 30)
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
}

报错信息:

(2) 缺省参数不能在定义和声明同时出现,那给谁呢?

        答案是:给函数声明,应该在函数声明中指定缺省值,并将该声明放在合适的头文件中。

代码演示:

Func.h文件:

#include<iostream>

using namespace std;

void Func(int a, int b = 20, int c = 30);

Func.cpp文件:

#include"Func.h"

void Func(int a, int b , int c )
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
}

test.cpp文件:

#include"Func.h"

int main()
{
	Func(1);
	Func(1, 2, 3);
	return 0;
}

说明:

1、详解编译+链接:

        程序的从源文件到执行程序,是经过翻译环境才到执行环境的,翻译环境又分为编译和链接。编译时源文件各走各的通过编译过程分别转化成目标代码,每个目标文件由链接器捆绑在一起,形成一个单一而完整的可执行程序。

        (1)编译又分为预编译、编译、汇编三个部分:①预编译时,它会完成头文件的包含(即:它会打开指定的头文件,并将其中的代码插入到包含该指令的源文件中,然后再进行编译);②编译时进行语法分析、词法分析、语义分析、符号汇总,将C++代码转换成汇编代码;③汇编时生成符号表,把汇编代码转换成机器指令(二进制指令)。

        (2)链接(链接器):把多个目标文件和链接库进行链接:①合成段位;②符号表的合并和重定位。

2、缺省参数一般在函数声明中指定缺省值,并将该声明放在合适的头文件中。因为编译时每个源文件都是独立转换为目标文件的,如果不在函数声明中指定缺省值在函数定义中指定缺省值,那test.cpp文件在编译过程的第二个步骤,编译时语法不通过,如图:

在声明的时候,有缺省值,函数调用时没有传参,就编译时就默认使用指定的缺省值,没有缺省值,函数调用时就必须传参。

二、函数重载

        自然语言中,一个词可以有多重含义,人们可以通过上下文来判断该词真正的含义,即该词被重载了。

1、函数重载概念

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

(1)参数类型不同

int Add(int left, int right)
{
	cout << "int Add(int left, int right)" << endl;
	return left + right;
}
double Add(double left, double right)
{
	cout << "double Add(double left, double right)" << endl;
	return left + right;
}
int main()
{
	Add(10, 20);
	Add(10.1, 20.2);
	return 0;
}

运行结果:

(2)参数个数不同

#include<iostream>

using namespace std;

void f()
{
	cout << "f()" << endl;
}
void f(int a)
{
 cout << "f(int a)" << endl;
}

int main()
{
	f();
	f(10);
	return 0;
}

运行结果:

(3)参数类型顺序不同

#include<iostream>

using namespace std;

void f(int a, char b)
{
	cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
	cout << "f(char b, int a)" << endl;
}

int main()
{
	f(10, 'a');
	f('a', 10);
	return 0;
}

运行结果:

说明:

1、调用重载函数时有三种可能的结果:

        (1)编译器找到一个与实参最佳匹配(匹配重载函数的顺序:首先寻找一个精确匹配,如果能找到,调用该函数;其次进行提升匹配,通过内部类型转换(窄类型到宽类型的转换)寻求一个匹配,如char到int、short到int等,如果能找到,调用该函数;最后通过强制类型转换寻求一个匹配,如int到double等,如果能找到,调用该函数。)的函数,并生成调用该函数的代码。

        (2)找不到任何一个函数与调用的实参匹配,此时编译器发出无匹配的错误信息。

        (3)有多于一个函数可以匹配,但是每一个都不是明显的最佳选择。此时也将发生错误,称为二义性调用。

2、尽管函数重载能在一定程度上减轻我们为函数起名字、记名字的负担,但是最好只重载那些确实非常相似的操作。

注意(混淆点):

1、函数重载对返回值没有要求:返回值不同,其他所有要素(函数名、形参列表)都相同,不构成重载。

2、二义性调用:可构成重载函数,但是对于重载函数的调用不明确。

讲解:

        (1)二义性调用:可构成重载函数,但是对于重载函数的调用不明确。

        代码演示:当函数重载使用缺省参数时,注意二义性调用

#include<iostream>

using namespace std;

void f()
{
	cout << "f()" << endl;
}
void f(int a = 10)
{
 cout << "f(int a)" << endl;
}

int main()
{
	f();//err,对函数重载的调用不明确
	f(10);//ok
	return 0;
}

2、C++支持函数重载的原理——名字修饰

        为什么C++支持函数重载,而C语言不支持函数重载呢?

        在C/C++中,一个程序要运行起来,需要经历以下几个阶段:预处理、编译、汇编、链接

        我们写一个简单的代码,实例分析让大家更容易理解:

Add.cpp文件:

int Add(int x, int y)
{
	return x + y;
}
double Add(double x, double y)
{
	return x + y;
}

Add.h文件:

int Add(int x, int y);

double Add(double x, double y);

test.cpp文件:

#include"Add.h"

int main()
{
	Add(1, 2);
	Add(1.1, 2.2);

	return 0;
}

说明:

1、实际项目通常是由多个头文件和多个源文件构成的,去上面两张图,我们可以知道,在预处理、编译、汇编三个阶段源文件独立完成,各走各的分别转化成目标代码,在链接阶段每个目标文件由链接器捆绑在一起,形成一个单一而完整的可执行程序。

2、我们发现在编译后链接前,test.o的目标文件中没有Add的函数地址,因为Add定义在Add.cpp中的,所以Add的地址在Add.o中。所以链接阶段就是专门处理这种问题,链接器看到test.o调用Add,但是没有Add的地址,就会到Add.o的符号表中找Add的地址,然后链接到一起。

3、为什么test.i阶段,test.i没有Add函数没有报错了,因为有Add函数的声明——声明就像承诺。链接——找到Add的定义,兑现承诺。

4、我们发现Add函数的名字在编译过程发生了改变——这里每个编译器都有自己的函数名修饰规则。

5、由于Windows下vs的修饰规则过于复杂,而Linux下g++的修饰规则简单易懂,下面我们使用g++演示了这个修饰的名字。

6、通过下面我们可以看出gcc的函数修饰后名字不变。而g++的函数修饰变成【_Z+函数长度+函数名+类型首字母】。

        (1)采用C语言编译器编译后的结果:

        结论:在Linux下,采用gcc编译完成后,函数名字的修饰没有发生改变。

        (2)采用C++编译器后结果:

        结论:在Linux下,采用g++编译完成后,函数名字的修饰发生改变,编译器将函数参数类型信息添加到修改后的名字中。

7、通过这里我们就理解了C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持重载。

8、如果两个函数函数名和参数是一样的,返回值不同是不构成重载的,因为调用时编译器没有办法区分。 

今天我们讲解了C++的缺省函数和重载函数,后续再有一节讲解引用、内联函数、auto关键字等我们就结束C++入门了。

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

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

相关文章

CompletableFuture真香,可以替代CountDownLatch!

1、背景 之前我们提到了 Future 和 Promise。Future 相当于一个占位符&#xff0c;代表一个操作将来的结果。一般通过 get 可以直接阻塞得到结果&#xff0c;或者让它异步执行然后通过 callback 回调结果。 但如果回调中嵌入了回调呢&#xff1f;如果层次很深&#xff0c;就是…

Spring Cloud Alibaba 快速上手搭建公司项目(四)Sentinel

Sentinel是一个开源的云原生流量控制和熔断降级的组件&#xff0c;它可以实现对微服务架构中的服务进行实时监控、自动降级、熔断限流等功能。Sentinel的核心原理是通过滑动窗口的方式对请求进行控制&#xff0c;当请求超过阈值时&#xff0c;会自动触发熔断操作&#xff0c;避…

JavaWeb——JSP实现书城首页

实验名称&#xff1a; JSP实现书城首页 实验目的&#xff1a; &#xff08;1&#xff09;了解JSP的特点及其运行原理 &#xff08;2&#xff09;掌握JSP的基本语法 &#xff08;3&#xff09;熟悉JSP指令和隐式对象的使用 &#xff08;4&#xff09;掌握JSP动作元素的使用…

ABP VNext 利用QQ邮箱发送邮件

ABP VNext 利用QQ邮箱发送邮件 1.配置邮箱1.1 设置1.2账户1.3 开启邮箱服务1.4 生成授权码 2 默认的SmtpEmailSender发送邮件2.1 生成数据库2.2 添加一个后台任务执行发送邮件2.3 服务中注入ISmtpEmailSender2.4 在配置文件添加邮箱信息 3 集成MailKit发送邮件3.1 添加包Volo.A…

从Docker和Kubernetes看Containerd

导读&#xff1a; 在学习Containerd之前&#xff0c;我们需要去了解Docker与Kubernetes这两个使用Containerd最多的技术&#xff0c;也需要明白什么是容器&#xff0c;什么是容器运行时&#xff0c;以及里面涉及的组件&#xff0c;这些组件是用来干什么的&#xff0c;及容器领域…

Zabbix Httpd漏洞修复2

一、背景 漏洞库升级的真是快啊&#xff0c;绿盟扫描的zabbix服务器又有新的漏洞了&#xff0c;经一番折腾&#xff0c;搞定&#xff0c;记录如下。 二、漏洞内容 漏洞主要还是集中在php和http漏洞 三、修复过程 思路还是升级httpd版本解决。 1、查看下zabbix版本&#xff…

【JVM】垃圾回收机制

垃圾回收三大步骤&#xff1a;判断是不是垃圾(垃圾判断算法) -> 标记需要回收的垃圾(三色标记) -> 回收垃圾(垃圾回收算法)。 一、如何判断是不是垃圾&#xff08;垃圾判断算法&#xff09;&#xff1f; &#xff08;1&#xff09;引用计数器算法&#xff1a;对象中记录…

基于STM32F103C8T6的超声波测距——串口输出

文章目录 前言一、超声波模块介绍1、产品特点2、超声波模块的时序图 二、STM32CubeMx创建工程1、配置项目2、keil代码设置3、效果 三、总结四、参考资料 前言 环境&#xff1a; 1、硬件&#xff1a;stm32f103c8t6 核心板 2、软件&#xff1a;STM32CubeMX 6.4.0 3、软件&#xf…

进程通信管道制作

利用父子进程 创建管道利用pipe函数 // 1.创建管道int pipefd[2] {0}; //[0] 读端 &#xff0c;[1]写端int n pipe(pipefd);assert(n ! -1); // debug 在release下会裁减(void)n;//防止在release下报错cout << "fd[0]:" << pipefd[0] << endl…

多用户商城开源-多店铺商城系统平台开发

多用户商城开源是指一种基于开放源代码的电子商务平台&#xff0c;允许多个用户共享一个平台&#xff0c;每位用户可以创建自己的电子商城&#xff0c;并在平台上进行交易、管理、营销等操作。多用户商城开源通常包含多种功能&#xff0c;如商品管理、订单管理、支付集成、促销…

vue diff算法与虚拟dom知识整理(14) patchVNode处理子节点新增和删减

上文 vue diff算法与虚拟dom知识整理(13) 手写patch子节点更新换位策略 我们实现了子节点位置的更新策略 但还有一些匹配不到的情况会导致死循环 那么我们继续来优化一下 我们先将src下的 index.js 代码改成这样 import h from "./snabbdom/h"; import patch from …

Scrapy ImagesPipeline下载图片

一、 ImagesPipeline是啥 ImagesPipeline是scrapy自带的类&#xff0c;用来处理图片(爬取时将图片下载到本地)。 二、ImagesPipeline优势&#xff1a; 将下载图片转换成通用的jpg和rgb格式避免重复下载缩略图生成图片大小过滤异步下载 三、ImagesPipeline工作流程 爬取一个…

Echarts构建指定省份的地图

1. 自行准备好Echarts环境 Echarts官网&#xff1a;https://echarts.apache.org/zh/index.html 2. 下载需要的省份或者城市的json地理信息文件 下载我们需要显示地区的Json数据&#xff0c;这个Json数据用于Echart的地图显示 例如我这里是下载的&#xff1a;湖南、湖北、四川…

同步模式之顺序控制线程执行

tip: 作为程序员一定学习编程之道&#xff0c;一定要对代码的编写有追求&#xff0c;不能实现就完事了。我们应该让自己写的代码更加优雅&#xff0c;即使这会费时费力。 文章目录 一、同步模式之顺序控制线程执行二、代码样例三、三个线程分别输出a、b、c&#xff0c;按顺序输…

作为一个项目管理成员,怎样才能有效监控项目执行?

作为一个项目管理成员&#xff0c;有效监控项目执行是确保项目成功的关键。在项目执行期间&#xff0c;您需要密切关注项目进展&#xff0c;并及时采取行动来纠正任何偏差。以下是几个有效的方法&#xff0c;可以帮助您监控项目执行并确保项目按计划顺利进行。 1. 制定详细的项…

C语言进阶--数据的存储

目录 数据类型介绍 基本内置类型&#xff1a; 类型的意义&#xff1a; 类型的基本归纳&#xff1a; 整型在内存中的存储 原码&#xff0c;反码和补码&#xff1a; 大小端存储模式&#xff1a; 大小端产生原因&#xff1a; 浮点型在内存中的存储 数据类型介绍 基本内…

六、机械手的种类

机械手是机器人能够完成指令的一个重要输出装置&#xff0c;机器臂是否合理、有效&#xff0c;决定了机 器人能否发挥出应有的作用。 机械手是一种能模仿人手和臂的某些动作功能&#xff0c;用以按固定程序抓取、搬运物件或操作工具的自动操作装置。特点是可以通过编程来完成各…

wy的leetcode刷题记录_Day68

wy的leetcode刷题记录_Day68 声明 本文章的所有题目信息都来源于leetcode 如有侵权请联系我删掉! 时间&#xff1a;2023-6-6 前言 目录 wy的leetcode刷题记录_Day68声明前言1019. 链表中的下一个更大节点题目介绍思路代码收获 1019. 链表中的下一个更大节点 2352. 相等行列…

CPU、内存、缓存的关系

术语解释 &#xff08;1&#xff09;CPU&#xff08;Central Processing Unit&#xff09; 中央处理器 &#xff08;2&#xff09;内存 内存用于暂时存放CPU中的运算数据&#xff0c;以及与硬盘等外部存储器交换的数据。它是外存与CPU进行沟通的桥梁&#xff0c;内存的运行决定…

Docker容器管理

docker容器相当于一个进程&#xff0c;性能接近于原生&#xff0c;几乎没有损耗&#xff1b; docker容器在单台主机上支持的数量成百上千&#xff1b; 容器与容器之间相互隔离&#xff1b; 镜像是创建容器的基础&#xff0c;可以理解镜像为一个压缩包 docker容器的管理 容…