Skip to content
On this page

函数默认参数

在C++中,定义函数时可以给形参指定一个默认的值,这样调用函数时如果没有给这个形参赋值(没有对应的实参),那么就使用这个默认的值。

也就是说,调用函数时可以省略有默认值的参数。如果用户指定了参数的值,那么就使用用户指定的值,否则使用参数的默认值。

所谓默认参数,指的是当函数调用中省略了实参时自动使用的一个值,这个值就是给形参指定的默认值。

数值指定

数值指定函数默认参数是最简单的形式,只用在参数后面添加对应值

下面是一个简单的示例:

cpp
#include<iostream>
using namespace std;

//带默认参数的函数
void func(int n, float b=1.2, char c='@') {
    cout << n << ", " << b << ", " << c << endl;
}

int main() {
    //为所有参数传值
    func(10, 3.5, '#');
    //为n、b传值,相当于调用func(20, 9.8, '@')
    func(20, 9.8);
    //只为n传值,相当于调用func(30, 1.2, '@')
    func(30);
}

运行结果

txt
10, 3.5, #
20, 9.8, @
30, 1.2, @

本例定义了一个带有默认参数的函数func(),并在main()函数中进行了不同形式的调用。

为参数指定默认值非常简单,直接在形参列表中赋值即可,与定义普通变量的形式类似。指定了默认参数后,调用函数时就可以省略对应的实参了。

表达式指定

默认参数除了使用数值常量指定,也可以使用表达式指定

例如

cpp
float d = 10.8;

void func(int n, float b=d+2.9, char c='@'){
    cout << n << ", " << b << ", " << c << endl;
}

默认参数位置

C++规定,默认参数只能放在形参列表的最后,而且一旦为某个形参指定了默认值,那么它后面的所有形参都必须有默认值。

这是因为实参和形参的传值是从左到右依次匹配的,默认参数的连续性是保证正确传参的前提。

下面的写法是正确的

cpp
void func(int a, int b=10, int c=20) { }
void func(int a, int b, int c=20) { }

但这样写不可以

cpp
void func(int a, int b=10, int c=20, int d) { }
void func(int a, int b=10, int c, int d=20) { }

默认参数并非编程方面的重大突破,而只是提供了一种便捷的方式。在以后设计类时你将发现,通过使用默认参数,可以减少要定义的析构函数、方法以及方法重载的数量。

本节的例子中,我们在函数定义处指定了默认参数。

除了函数定义,你也可以在函数声明处指定默认参数。不过当出现函数声明时情况会变得稍微复杂,很多书籍也对这点含糊其辞,在这里我会对其详细解释

到底在声明中还是定义中指定默认参数

结论:

  • 函数定义和声明在同一个文件内时,在声明处指定
  • 函数定义和声明不在同一个文件内时,声明处一定要指定,定义处无所谓

上节的例子中,我们在函数定义处指定了默认参数。除了函数定义,你也可以在函数声明处指定默认参数。不过当出现函数声明时情况会变得稍微复杂,有时候你可以在声明处和定义处同时指定默认参数,有时候你只能在声明处指定

请看下面的示例1

cpp
#include <iostream>
using namespace std;

void func(int a, int b = 10, int c = 36);

int main() {
    func(99);
    return 0;
}

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

WARNING

这段代码在编译时会报错,错误信息表明不能在函数定义和函数声明中同时指定默认参数。

对代码稍作修改,将 func() 函数的定义放到其他源文件中,如下示例2所示。

main.cpp 代码

cpp
#include <iostream>
using namespace std;

void func(int a, int b = 10, int c = 36);

int main() {
    func(99);
    return 0;
}

module.cpp 代码

cpp
#include <iostream>
using namespace std;

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

运行结果:

txt
99, 10, 36

修改后的代码是可以编译通过的,这有点让人摸不着头脑,为什么将func()的定义放到其他源文件中就不一样了呢?

这是因为 C++ 规定,在给定的作用域中只能指定一次默认参数。

对于示例1,func() 的定义和声明位于同一个源文件,它们的作用域也都是整个源文件,这样就导致在同一个文件作用域中指定了两次默认参数,违反了 C++ 的规定。

对于示例2,func() 的声明位于main.cpp,作用域也是main.cpp,而 func() 的定义位于module.cpp,作用域也是module.cppfunc() 的声明和定义位于不同的作用域,相互之间不影响。

C 语言有四种作用域,分别是函数原型作用域、局部作用域(函数作用域)、块作用域、文件作用域(全局作用域),C++ 也有这几种作用域。

继续对代码进行修改,将 func() 定义处 bc 的默认值分别设置为 557,而声明处 bc 的默认值不变,依然为 1036。编译并运行程序,发现输出结果与上面一样,这说明编译器使用的是当前作用域中的默认参数。站在编译器的角度看,它不管当前作用域中是函数声明还是函数定义,只要有默认参数就可以使用。