3.3 默认实参

简介

Tips:一旦某个形参被赋予了默认值,那么它后面的所有形参都必须有默认值。

某些函数包含一类形参,它们在函数的很多次调用中都被赋予了一个相同的值,我们将这个反复出现的值称为函数的默认实参。调用含有默认实参的函数时,可以包含该实参,也可以省略该实参:

typedef string::size_type sz;
string screen(sz ht = 24, sz wid = 80, char backgrnd = ' ');

string window;
window = screen();              // screen(24, 80, ' ')
window = screen(66);            // screen(66, 80, ' ')
window = screen(66, 256);       // screen(66, 256, ' ')
window = screen(66, 256, '#');  // screen(66, 256, '#')

编码规范:只允许在非虚函数中使用默认实参,且必须保证默认实参的值始终一致。不建议使用默认实参,一般情况下建议使用函数重载(默认实参实际上就是函数重载语义的另一种实现方式),因为默认实参会干扰函数指针,导致函数签名与调用点的签名不一致,而函数重载不会导致这样的问题。

Tips:可以在构造函数中使用默认实参,毕竟不可能取得它们的地址。

声明

在给定的作用域内,一个形参只能被赋予一次默认实参(因为两个函数都是最佳匹配,会导致二义性调用的错误),但是可以给其他的形参添加默认实参:

typedef string::size_type sz;
string screen(sz, sz, char = ' ');
string screen(sz, sz, char = '*');      // 错误: 重复声明
string screen(sz = 24, sz = 80, char);  // 正确: 添加默认实参

表达式作为默认实参的初始值

局部变量不能作为默认实参,但是只要表达式的类型能转换成形参所需的类型,那么该表达式就能作为默认实参初始值:

sz wd = 80;
char def = ' ';
sz ht();
// 函数声明
string screen(sz = ht(), sz = wd, char = def);

// 函数调用: 等价于screen(ht(), 80, ' ')
string window = screen();

// 函数调用
void foo() {
    def = '*';          // 改变默认实参def的值
    sz wd = 100;        // 隐藏了外层定义的wd, 但是没有改变默认值
    window = screen();  // 等价于screen(ht(), 80, '*')
}