第6.5章: 默认实参
概述
C++ 允许函数形参带有默认值。 当调用者省略某个实参时,就使用该默认值。
在本章中,你将学到:
- 如何定义默认实参
- 为什么默认值应放在声明里,而不是定义里
- 带默认值的形参在顺序上的规则
- 默认实参如何与重载交互
- 默认实参在何时求值
1. 基本默认实参
默认实参在参数列表中用 = value 指定。
void scale(int x, int factor = 2)
{
::fast_io::io::println(x * factor);
}
int main()
{
scale(10); // uses default factor = 2
scale(10, 5); // uses factor = 5
}
默认实参最适合配合内建类型使用,因为它们既廉价 又无歧义。
2. 默认实参应当放在声明中
默认实参应当出现在函数声明中, 而不是定义中。 这样可避免重复定义问题,并让头文件自给自足。
// header (math.hpp)
int power(int base, int exp = 2);
// source file (math.cpp)
int power(int base, int exp)
{
int result{1};
for(int i{}; i < exp; ++i)
result *= base;
return result;
}
如果你在两个地方都写默认值,编译器会拒绝这段代码。
3. 默认实参的顺序规则
一旦某个形参有了默认值,它右边的所有形参也必须 有默认值。
void f(int x = 0, int y = 0); // ✔ OK
void g(int x = 0, int y); // ❌ error — y has no default
这条规则确保调用不会产生歧义。
4. 与函数重载的交互
默认实参和重载可能以出人意料的方式相互作用。
void h(int x, int y = 0);
void h(int x);
像 h(5) 这样的调用会有歧义:
- 第二个重载直接匹配
- 第一个重载使用默认值也能匹配
除非设计非常清晰,否则请避免混用重载与默认实参。
5. 默认实参何时求值
默认实参在调用点求值,而不是在 函数定义处。
int next_id()
{
static int counter{};
return ++counter;
}
void assign_id(int id = next_id());
int main()
{
assign_id(); // id = 1
assign_id(); // id = 2
}
每次调用都会重新对默认表达式求值。
要点
- 当调用者省略形参时,默认实参提供后备值。
- 默认值应放在声明中,而不是定义中。
- 一旦某个形参有默认值,它右边的所有形参也必须有默认值。
- 默认实参在调用点求值。
- 混用重载与默认实参可能导致歧义。
- 默认值请使用内建类型;避免使用沉重的用户定义类型。