文章目录
前言1. 什么是缺省参数?2. 缺省参数的分类2.1 全缺省【备胎是如何使用的?】2.1.1 疑难细究 2.2 半缺省2.2.1 错误用法示范2.2.2 正确用法示范2.2.3?实参缺省与形参缺省的混合辨析? 3. 缺省参数的规则和限制4. 规定必须函数声明给缺省值5. 缺省参数 vs 重载函数6. 其它常见问题和注意事项6.1 缺省参数的表达式计算时机6.2 静态和可变参数问题 结语
前言
C++中的缺省参数使得函数调用更加灵活,减少了重复代码,提高了代码的可读性。然而,使用时必须遵守一些规则,如顺序要求和声明与定义中只能出现一次。理解这些规则和限制可以帮助开发者更好地利用C++的强大特性,编写出更加简洁和高效的代码。
1. 什么是缺省参数?
在函数设计中,缺省参数(也称为默认参数)是指函数参数可以在调用时被省略,省略的参数会自动使用预定义的默认值。这使得函数的调用更加灵活,无需为每个参数显式传递值。
在C++中,缺省参数允许程序员在声明或定义函数时为参数提供默认值。例如,以下是一个简单的函数声明:
int my_func(int a, int b, int c = 12);
在这个例子中,c有一个缺省值12。这意味着当调用my_func(1, 2)
时,c
的值自动为12。如果调用my_func(1, 2, 3)
,则c
的值会被显式传递的值3
覆盖。
2. 缺省参数的分类
缺省参数分为全缺省和半缺省参数。
全缺省指所有的函数参数都有默认值,这使得调用函数时可以选择传递所有参数、部分参数,甚至不传参数。
半缺省是指部分参数有默认值,通常从右向左依次进行缺省。
2.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);
下面这种应该不用我说了,典型的绿茶?使用的都是三个缺省值10、20、30【早上让备胎一号早起帮忙买早饭,中午和备胎2号去高档餐厅吃饭,晚上和备胎3号去湖边约会】 func();
来看一下运行结果。和我上面解释是一样的
2.1.1 疑难细究
可以看出,刚才我都是执行【从右往左依次连续给出缺省值】的,但若是我像下面这样传递参数的话,虽然是规则对的,但语法是错误的。
func(, 1);func(, 1, 2);func(, , 1);
结果如下:
2.2 半缺省
2.2.1 错误用法示范
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)
结果如下:
2.没有连续地给出缺省值
对于第二种而言就是的虽然最后一个缺省值给出了,并且第一个缺省值也给出了,但是呢第二个缺省值却没有给出,这其实出现问题了,因为存在不连续的缺省值上面说到过,若是想要给出第1个缺省值,那么那么第2个和第3个都必须给出void func(int a = 10, int b, int c = 30)
2.2.2 正确用法示范
通过对比可以发现下面的这些全部满足【从右往左依次连续给出缺省值】,满足了若是前一个有缺省值后一个也连续的也必须有缺省值的条件
void func(int a, int b = 20, int c = 30)//✔后两个缺省void func(int a, int b, int c = 30)//✔最后一个缺省
2.2.3?实参缺省与形参缺省的混合辨析?
1.第一形参无缺省,至少传入一个实参
void func(int a, int b = 20, int c = 30)
func(1, 2, 3);//a = 1 b = 2 c = 3func(1, 2);//a = 1 b = 2 c = 30func(1);//a = 1 b = 20 c = 30func();//a = ? b = 20 c = 30
可以看到,因为第一个形参没有给出缺省参数值,所以在传参的时候必须给到形参a一个值,可以看出编译器检查得严格,若是检查得不严格那么打印出来的就是一个随机值
2.第一、二形参无缺省,至少传入两个实参
void func(int a, int b, int c = 30)
func(1, 2, 3);//a = 1 b = 2 c = 3func(1, 2);//a = 1 b = 2 c = 30func(1);//a = 1 b = ? c = 30func();//a = ? b = ? c = 30
此时,当前两个形参都没有缺省参数值时,那么在传参的时候就必须给形参a和形参b都传入一个值,那就是必须要传入两个值,可以不传入第3个实参,因为第三个形参有默认缺省值
3.三个形参均无缺省值,需传入三个实参
void func(int a, int b, int c)
func(1, 2, 3);//a = 1 b = 2 c = 3func(1, 2);//a = 1 b = 2 c = ?func(1);//a = 1 b = ? c = ?func();//a = ? b = ? c = ?
最后这一种,就是当所有的形参缺省值都没有给出的时候,此时就是我们写的正常函数形式,三个形参就必须传入三个实参,缺一不可
3. 缺省参数的规则和限制
顺序要求:缺省参数必须从右向左定义,不能跳跃。如果函数中有多个参数,未缺省的参数必须在最左边。
缺省参数不能在函数声明和定义中同时出现:缺省参数只能在函数的声明或定义中出现一次,不能同时出现在声明和定义中。若是在声明和定义中同时给出函数的缺省参数,此时就会出现【重定义默认参数】的问题。下面我所给出的值是相同的,若是两边给出的值不同的话,编译器在编译的时候就会产生歧义,不知道使用那一块的参数。
缺省值必须是常量或全局变量:缺省值必须是编译时已知的值,不能是局部变量或运行时动态计算的值。这一点很好理解,你给出的缺省值必须是一个固定的值,而不是一个可修改的变量,否则这个缺省值将毫无意义;对于缺省值一般我们不会使用全局变量,因为全局变量会存在线程安全的问题,日常写代码也是不推荐使用全局变量。
C语言不支持(编译器不支持)。演示一下,创建了一个test.c
的源文件的,然后和上面一样为这里的函数形参给到缺省值,接着去编译的话就可以发现是会出现很多错误的,这其实就可以看出C语言是不支持【缺省参数】的。 4. 规定必须函数声明给缺省值
缺省参数不能在函数声明和定义中同时出现,因为如果我们声明和定义如果默认参数不一致的话,我们应该听谁的呢?比如在声明中默认参数是4,而到了定义中默认参数是40,那到底默认参数是几呢?故缺省参数不能在函数声明和定义中同时出现。
那么缺省参数到底是声明给呢还式定义给呢?
1.首先我们先来看看缺少参数给定义是什么结果?
我们发现如果定义给的话报错了,主要问题就是函数不接受一个参数。
✍首先在编译阶段的预处理阶段,在两个.cpp文件中展开.h头文件,两个.cpp文件在编译阶段各走各的(在链接阶段才会合到一起)。
这里出错是在编译阶段就报错了,因为我们包含的头文件是.h,而.h文件中只有声明没有定义而编译器在处理的时候发现一开始传参传了两个参数,后来就值传了一个参数,请看下图:
2.然后我们先来看看缺少参数给声明是什么结果?
这里我们发现程序是可以正常运行的,当编译器处理StackInit(&st1, 100);
的时候按照正常传参即可(跟缺省参数没有什么关系);而当编译器处理StackInit(&st2);
的时候,我们由于在声明中给了缺省,所以编译器在编译的时候,我们可以认为编译器会把StackInit(&st2);
转换为StackInit(&st2,4);
,所以对于函数定义而言根本不需要关心到底是不是缺省的,因为函数定义的时候都要传两个参数给它,所以声明调用的时候如果只有一个参数,会转换成两个参数。故缺省参数声明给而定义不给。
5. 缺省参数 vs 重载函数
在一些语言中,如Java,缺省参数并不被支持。为了模拟缺省参数的功能,通常通过重载函数来实现。例如:
int MyFunc(int a, int b) { return MyFunc(a, b, 12); // 缺省参数通过调用重载的函数实现}int MyFunc(int a, int b, int c) { // 主实现}
虽然这也能达到类似效果,但代码较为冗余,缺省参数在C++中显然更加简洁易用。
6. 其它常见问题和注意事项
6.1 缺省参数的表达式计算时机
当缺省参数是一个表达式时,表达式的计算时机是编译时还是运行时需要注意。在C++中,缺省参数的值是在函数调用时计算的,而非函数声明时。这与Python中缺省参数的行为不同,Python会在模块加载时计算默认参数。
6.2 静态和可变参数问题
在Python等语言中,如果缺省参数是可变类型(如列表),则它会被静态分配,即在所有函数调用中共享这个参数。这会带来意外的副作用。为避免此问题,可以使用监视哨值(如None
),并在函数内部进行初始化,例如:
def f(a, b=None): b = b or []
结语
今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连支持一下。
也可以点点关注,避免以后找不到我哦!
Crossoads主页还有很多有趣的文章,欢迎小伙伴们前去点评,您的支持就是作者前进的动力!
参考:https://juejin.cn/post/7222274630396198971
https://developer.aliyun.com/article/1217073