1. 形参默认值要从右向左给
先看一个简单的示例代码:
#include <iostream> using namespace std; int sum(int a, int b) // sum函数的两个形参都没有给默认值 { return a + b; } int main() { int x = 10; int y = 20; int ret = sum(x, y); return 0; }那么我们给出默认值:
#include <iostream> using namespace std; int sum(int a = 30, int b) { return a + b; } int main() { int y = 20; int ret = sum(y); return 0; }这里的想法是把 y 传给 b ,a 用默认参数 30 ,那么此时就会报错:“sum”: 缺少形参 2 的默认实参
因为 C++ 调用函数时,实参是按位置从左到右匹配形参的!!!
编译器在调用函数的时候,发现 sum(y) 没有第二个参数,也没有默认值,所以会报错
那么我们给默认值的时候就要求必须从右向左给!!!
#include <iostream> using namespace std; int sum(int a, int b = 30) { return a + b; } int main() { int x = 20; int ret = sum(x); return 0; }此时返回的结果就是 50
2. 形参在给默认值的时候,不管是定义处给,还是声明处给,同一个形参默认值只能出现一次
我们看下面的代码
#include <iostream> using namespace std; int sum(int = 10, int); //这里声明一下函数 int main() { int ret = sum(); return 0; } int sum(int x, int y = 20) { return x + y; }但是这个代码还是会报错:“sum”: 缺少形参 2 的默认实参
这是因为声明处也必须遵守:默认参数必须从右往左连续提供的规则、
此外默认参数在调用点必须已经可见。代码从上到下执行,执行到:
int ret = sum();的时候,发现声明没有给出第二个默认参数,此时就会报错。
默认参数不是运行时才找的,而是在编译调用语句时就确定了。
再看下面这个代码:
#include <iostream> using namespace std; int sum(int, int = 10); int main() { int a = 30; int ret = sum(a); cout << ret << endl; return 0; } int sum(int x, int y = 20) { return x + y; }这个代码也会报错:“sum”: 重定义默认参数 : 参数 1
所以说不管是定义处,还是声明处,同一个形参的默认值只能给一次
再看下面这个代码:
#include <iostream> using namespace std; int sum(int, int = 10); int main() { int a = 30; int ret = sum(a); cout << ret << endl; return 0; } int sum(int x = 20, int y) { return x + y; }这个代码就不会报错,其原因是:默认参数可以在同一作用域的多次声明中逐步补充。
函数定义本身也是一次函数声明。相当于又给第一个参数 x补了默认值 20
所以两次声明合起来,相当于:
int sum(int x = 20, int y = 10);但是在main里面:
int ret = sum(a);此时编译器只看到了前面的声明,还没看到后面的定义。
所以在 main 这里,编译器只知道第二个参数有默认值 10 。
所以下面的代码时可以运行的:
#include <iostream> using namespace std; int sum(int, int = 10); int sum(int = 5, int); int main() { int ret = sum(); cout << ret << endl; //15 return 0; } int sum(int x, int y) { return x + y; }3.调用效率的问题 形参传入几个[变量]就有几个mov指令
那么现在我们从汇编指令的角度去探索一下形参默认值的效率问题
#include <iostream> using namespace std; //0 int sum(int x, int y) { return x + y; } int main_0() { int a = 10; int b = 20; /* 下面这句代码的函数调用对应的汇编指令是: 008B1A44 mov eax,dword ptr [b] 008B1A47 push eax 008B1A48 mov ecx,dword ptr [a] 008B1A4B push ecx 008B1A4C call sum (08B10D2h) */ int ret = sum(a, b); cout << ret << endl; return 0; } //1 int sum(int x, int y = 10) { return x + y; } int main_1() { int a = 10; /* 下面这句代码的函数调用对应的汇编指令是: 008A1A3D push 0Ah 008A1A3F mov eax,dword ptr [a] 008A1A42 push eax 008A1A43 call sum (08A10D2h) */ int ret = sum(a); cout << ret << endl; return 0; } //2 int sum(int x = 5, int y = 10) { return x + y; } int main_2() { /* 下面这句代码的函数调用对应的汇编指令是: 00D51A36 push 0Ah 00D51A38 push 5 00D51A3A call sum (0D510D2h) */ int ret = sum(a); cout << ret << endl; return 0; }从上面的指令可以看出,传入的变量个数有几个就会相应的产生几个mov指令。那么效率就会低一些。
再看下面的代码:
#include <iostream> using namespace std; int sum(int x, int y = 10) { return x + y; } int main() { int a = 11; /* 00DA1A3D mov eax,dword ptr [a] 00DA1A40 push eax 00DA1A41 push 1Eh 00DA1A43 call sum (0DA10D2h) */ int ret = sum(30, a); cout << ret << endl; return 0; }这里也可以体现处,传入的是变量才会产生对应的mov指令,否则会直接push传入的值。
总结
形参带默认值的函数
1.给默认值的时候从右向左给 不能写成 int sum(int a = 10, b)
2.调用效率的问题 形参传入几个[变量]就有几个mov指令
3.定义处可以给形参默认值,声明也可以给形参默认值
4.形参在给默认值的时候,不管是定义处给,还是声明处给,形参默认值只能出现一次