C++ | 详细介绍缺省参数的作用

474 阅读10分钟

本文正在参加「金石计划」

一、前言

1、缺省参数概念

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

  • 通俗点讲,就是在定义函数的时候可以给形参赋一个初始化的值,这个值就叫做缺省值,缺省值可以有一个,也可以有多个

2、缺省参数的使用规则

  1. 半缺省参数必须从右往左依次且连续来给出,不能间隔着给【实参和形参同理】
  • 可以通过下图先了解一下,下文我会详细介绍。可以看出对于形参中的缺省参数如果要给的话不可以随意给,要么从右往左给1个或者是2个,要么全部缺省,否则必须要连续。否则就不符合规定

在这里插入图片描述 2. 缺省参数不能在函数声明和定义中同时出现

  • 可以看到,若是在声明和定义中同时给出函数的缺省参数,此时就会出现【重定义默认参数】的问题。下面我所给出的值是相同的,若是两边给出的值不同的话,编译器在编译的时候就会产生歧义,不知道使用那一块的参数

在这里插入图片描述

  • 一般我们会选择定义在声明处,因为声明处的头文件其他.cpp文件可以包含。若是将这些缺省参数放在放在了定义出,其他文件就没办法使用到了

在这里插入图片描述 3. 缺省值必须是常量或者全局变量

  • 这一点很好理解,你给出的缺省值必须是一个固定的值,而不是一个可修改的变量,否则这个缺省值将毫无意义;对于缺省值一般我们不会使用全局变量,因为全局变量会存在线程安全的问题,日常写代码也是不推荐使用全局变量
  1. C语言不支持(编译器不支持)
  • 演示一下,创建了一个test.c的源文件的,然后和上面一样为这里的函数形参给到缺省值,接着去编译的话就可以发现是会出现很多错误的,这其实就可以看出C语言是不支持【缺省参数】的

在这里插入图片描述


因为对于缺省参数而言,虽然看上去很好理解,不过你真正去使用的话若是不注意会出现很多错误,了解了基本的概念和使用规则之后,接下去就让我们真正地去研究一下这个缺省参数

二、全缺省参数【备胎是如何使用的♿】

1、四种实参传递方式说明

  • 首先来看一下全缺省参数,对于全缺省参数而言全部的形参值都给上一个缺省值,也就像下面这样
void func(int a = 10, int b = 20, int c = 30)
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
}
  • 然后我们便可以试着是去调用一下这个函数,因为有缺省参数的存在,可以不考虑传入全部的值,首先对于下面这种就是最常见的,那也就是传入所有的参数。【假设默认缺省值均为备胎,a为备胎1号,b为备胎2号,c为备胎3号】那么此时这样的传值是不需要备胎的
func(1, 2, 3);
  • 然后试着传入前两个实参试试,那此时最后一个使用的就是默认的缺省参数30,也就是备胎3号【今天晚上想看场电影,但是电影票有点贵,所以叫来备胎3号
func(1, 2);
  • 接下去试着只传入一个参数,那后面两个b和c使用的就是默认的缺省参数20和30【早饭自己家里吃,中午吃饭叫来备胎2号付钱,晚上和备胎3号吃完饭然后看电影
func(1);
  • 下面这种应该不用我说了,典型的绿茶:tea:使用的都是三个缺省值10、20、30【早上让备胎一号早起帮忙买早饭,中午和备胎2号去高档餐厅吃饭,晚上和备胎3号去湖边约会
func();

来看一下运行结果。和我上面解释是一样的

在这里插入图片描述

2、疑难细究

  • 可以看出,刚才我都是执行【从右往左依次连续给出缺省值】的,但若是我像下面这样传递参数的话,虽然是规则对的,但语法是错误的
func(, 1);
func(, 1, 2);
func(, ,1);

在这里插入图片描述

三、半缺省参数【⭐】

如果说全缺省参数比较好理解一些,那半缺省参数就够我们喝一壶了

【概念】:并不是所有的形参都有缺省值,可以缺省一个,也可以缺省多个

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

例如像上面这种就是典型的半缺省参数

1、错误用法示范

==① 没有从右往左进行缺省==

  • 对于下面三种而言,就是非常明显得没有从右往左去给出缺省值,只是给出了前两个缺省值或者是给出了第一个或者第二个缺省值
  • 若是想要给出第2个缺省值,那么第3个就必须给出;若是想要给出第1个缺省值,那么那么第2个和第3个就必须给出
void func(int a = 10, int b = 20, int c)
void func(int a = 10, int b, int c)
void func(int a, int b = 20, int c)

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

==② 没有连续地给出缺省值==

  • 对于第二种而言就是的虽然最后一个缺省值给出了,并且第一个缺省值也给出了,但是呢第二个缺省值却没有给出,这其实出现问题了,因为存在不连续的缺省值
  • 上面说到过,若是想要给出第1个缺省值,那么那么第2个和第3个都必须给出
void func(int a = 10, int b, int c = 30)

在这里插入图片描述

2、正确用法示范

知道了怎样给缺省值是错误的之后我们来看看正确的半缺省参数应该如何给出

  • 通过对比可以发现下面的这些全部满足【从右往左依次连续给出缺省值】,满足了若是前一个有缺省值后一个也连续的也必须有缺省值的条件
void func(int a, int b = 20, int c = 30)		//✔	后两个缺省
void func(int a, int b, int c = 30)				//✔	最后一个缺省
  • 对于下面的这两种就比较特殊,第一个就是全部没有缺省值,那其实就是我们平时正常写函数的样子;而对于第二个就是全部给出缺省值,那其实也就是上面说到过的全缺省参数,对于它的调用方式比较多,我在上面已经演示过了
void func(int a, int b, int c)					//✔	全部不缺省(正常形参)
void func(int a = 10, int b = 20, int c = 30)	//✔	全部缺省【调用方式多】

🔥实参缺省与形参缺省的混合辨析🔥

通过了学习了半缺省参数,接下去我将带你通过实参传值,形参接收的形式,再度来辨析一下【半缺省参数】的难点究竟在哪里

  1. 第一形参无缺省,至少传入一个实参
void func(int a, int b = 20, int c = 30)
func(1, 2, 3);		//a = 1  b = 2  c = 3
func(1, 2);			//a = 1  b = 2  c = 30
func(1);			//a = 1  b = 20 c = 30
func();				//a = ?  b = 20 c = 30
  • 可以看到,因为第一个形参没有给出缺省参数值,==所以在传参的时候必须给到形参a一个值==,可以看出编译器检查得严格,若是检查得不严格那么打印出来的就是一个随机值

在这里插入图片描述


  1. 第一、二形参无缺省,至少传入两个实参
void func(int a, int b, int c = 30)
func(1, 2, 3);		//a = 1  b = 2  c = 3
func(1, 2);			//a = 1  b = 2  c = 30
func(1);			//a = 1  b = ?  c = 30
func();				//a = ?  b = ?  c = 30
  • 此时,当前两个形参都没有缺省参数值时,==那么在传参的时候就必须给形参a和形参b都传入一个值==,那就是必须要传入两个值,可以不传入第3个实参,因为第三个形参有默认缺省值

在这里插入图片描述


  1. 三个形参均为缺省参数,需传入三个实参
void func(int a, int b, int c)
func(1, 2, 3);		//a = 1  b = 2  c = 3
func(1, 2);			//a = 1  b = 2  c = ?
func(1);			//a = 1  b = ?  c = ?
func();				//a = ?  b = ?  c = ?
  • 最后这一种,就是当所有的形参缺省值都没有给出的时候,此时就是我们在C语言中写的正常函数形式,==三个形参就必须传入三个实参,缺一不可==

在这里插入图片描述

3、小结

  • 形参缺省不是缺了一个值,而是给了一个默认参数值。
  • 不仅是在给出半缺省形参值时需要注意【从右往左依次连续给出】;在给具有半缺省参数的函数传递实参的时候,要注意传入实参的个数必须符合给出的缺省形参个数

四、缺省参数的实际应用 —— 栈

如果你认真自己地看下来,就会觉得大吃一惊,原来缺省参数还有这么多细节是被忽略的,那了解到这些之后可以带来什么实际的意义呢?

  • 可以看到,这是我们在数据结构 — 栈中写的代码,定义了一个栈的结构体和一个对其进行初始化的Init函数。在初始化时我将这个栈的大小设置为4,以及这个容量大小Capacity也为4
struct Stack {
	int* a;
	int top;
	int Capacity;
};

void InitStack(struct Stack* st)
{
	st->a = (int*)malloc(sizeof(int) * 4);
	st->top = 0;
	st->Capacity = 4;
}
  • 此时我在外界普通得定义了一个栈,然后对其去进行一个初始化,后续的话再对其进行一些入栈和出栈的操作,对于顺序栈来说可能会出现栈满容量不够的情况,所以在Push的时候会有一个扩容的逻辑
  • 但是一直这么容量不够去扩容的话也是会存在消耗的,因为我一开始给的只有4个空间的大小。但若是一开始就给到很大的容量比如说100,但是数据量只在10以内,这又会存在一个浪费的现象
struct Stack st;
InitStack(&st);

上面这种其实就是因为一开始初始化给到的栈容量太大或者太小导致的,若是我们在提前知道当前数据量的情况下可以手动给出栈的容量时,就不会导致这种情况了,此时就可以使用到我们本文所学习的【缺省参数】了

  • 此时我们可以对栈的初始化函数做一个改进,添加一个defaultCapacity默认容量这个参数,然后为其设置一个缺省参数为4
  • 从缺省参数的规则可以看出,【从右往左依次连续给出】没有问题,对于实参传递不会有问题,肯定不会忘了传入栈的地址,那么这个默认容量就可传可不传了
void InitStack(struct Stack* st, int defaultCapacity = 4)
{
	st->a = (int*)malloc(sizeof(int) * defaultCapacity);
	st->top = 0;
	st->Capacity = defaultCapacity;
}
  • 此处我定义了两个栈,因为知晓了第一个栈的数据量是80个,所以可以去手动初始化一个默认容量为100大小的栈;可以对于第二个栈,我不知道数据量的大小,此时我可以选择不传入实参,函数内部就会默认使用给出的缺省参数值4,那么这个栈的初始大小就为4
struct Stack st;
InitStack(&st, 100);

struct Stack st2;
InitStack(&st2);

这就是有关缺省参数实际应用的案例,当然不止这一个,我只是举个例子,在C++中有很多地方都会使用到这个【缺省参数】,比方说还有六大成员函数之一的==构造函数==若是你对其语法非常熟悉的话,用起来就会非常得顺手

五、总结与提炼

最后我们来总结一下本文所学习的内容

  • 在一开始,首先认识了什么叫做【缺省参数】,知道了其使用的一些规则
  • 接下去,我们学习了两种缺省参数的形式,一个是全缺省参数,一个则是半缺省参数。对于前者,我演示了四种实参传递的方式,向你展现了备胎是如何被使用的;对于后者,虽然看上去很简单,但若是细细地去研究其语法的话就会发现,还是存在许许多多的小细节需要注意的,最主要的就是要记住一点,对于缺省参数值一定要【从右往左依次连续给出
  • 最后,我们在学习了缺省参数后知道了如何去将其运用在实际的开发中,这一点需要在学习C++的过程中细细体会

以上就是本文要介绍的所有内容,感谢您的阅读:rose:

在这里插入图片描述