在声明与定义中指定默认参数的规则
在 C++ 中,默认参数只能在 同一作用域 中指定一次。理解这一规则,需要结合函数声明(declaration)与函数定义(definition)的作用域来分析。下面通过几个示例,说明在声明处和定义处如何正确地使用默认参数。
1. 同一源文件中重复指定——编译错误
#include <iostream>
using namespace std;
// 声明中指定了 b、c 的默认值
void func(int a, int b = 10, int c = 36);
int main() {
func(99); // 期待输出 99, 10, 36
return 0;
}
// 定义中又指定了 b、c 的默认值(重复指定)
void func(int a, int b = 10, int c = 36) {
cout << a << ", " << b << ", " << c << endl;
}
- 错误原因:声明和定义都位于同一源文件,属于同一作用域,重复给形参
b
和 c
指定默认值,违反了“同一作用域中只能指定一次默认参数”的规定。
2. 不同源文件中分别指定——可以编译
main.cpp
#include <iostream>
using namespace std;
// 在 main.cpp 中为 b、c 指定默认值
void func(int a, int b = 10, int c = 36);
int main() {
func(99); // 输出:99, 10, 36
return 0;
}
module.cpp
#include <iostream>
using namespace std;
// 在 module.cpp 中定义函数,并再次写出默认值
void func(int a, int b = 10, int c = 36) {
cout << a << ", " << b << ", " << c << endl;
}
- 可行原因:
main.cpp
与 module.cpp
分别独立编译,各自有独立的文件作用域。它们互不干扰,因此在两个文件中都“出现”了默认参数,却不算重复指定。
3. 作用域概述
C/C++ 中,作用域分为以下几种(主要关注文件作用域与函数原型作用域):
- 文件作用域(全局作用域):在一个源文件内,超出任何函数或类的范围。
- 函数原型作用域:函数声明中形参列表的作用域,只在声明处有效。
原则:在同一作用域内,每个形参只能被赋予一次默认值。
4. 多次声明同一函数,分步添加默认参数
如果在同一个文件(同一作用域)多次声明同一函数,只要每次声明 只为尚未指定默认值的参数添加默认值,且不重复赋值,就合法:
#include <iostream>
using namespace std;
// 第一次声明:只为 c 指定默认值
void func(int a, int b, int c = 36);
// 第二次声明:为 b 添加默认值,不重复给 c 指定默认值
void func(int a, int b = 5, int c);
// 函数定义:**不再**写出任何默认值
void func(int a, int b, int c) {
cout << a << ", " << b << ", " << c << endl;
}
int main() {
func(99); // 等价于 func(99, 5, 36),输出:99, 5, 36
func(99, 7); // 等价于 func(99, 7, 36),输出:99, 7, 36
func(99, 7, 8); // 直接传入所有实参,输出:99, 7, 8
return 0;
}
-
合法要点
- 第一次声明为
c
指定默认值;
- 第二次声明为
b
指定默认值,且不再为 c
指定默认值;
- 两次声明后,参数列表从左到右依次为:
a
(必选)、b=5
、c=36
。
5. 小结
- 同一作用域内,每个参数 只能 指定一次默认值。
- 声明处和定义处若处于同一源文件,只能 在其中一个位置给参数指定默认值。
- 在多文件编程中,声明(头文件或某源文件)与定义(其他源文件)各自拥有独立文件作用域,可分别出现默认参数。
- 对同一函数的多次声明,允许“逐步”为尚未指定默认值的参数添加默认值,但不能重复指定已有默认值的参数。