函数重载(overloading)是声明多个同名函数的机制,但其签名(参数的数量或类型)不同。
默认参数值可以在函数声明中指定。细微之处:默认值只在调用的编译期间考虑,并由编译器根据可见的签名进行填充。
在类中常常出现这样的情况:
class Printer { void print(int n, char c = '*') { /* ... */ } void print(const std::string& s) { /* ... */ } }; Printer p; p.print(5); // 调用 print(int n, char c = '*'), c = '*' p.print("Hi"); // 调用 print(const std::string&)
细微之处:
void foo(int x, int y = 10); void foo(int x); foo(1); // 错误:不清楚调用哪个函数
唯一允许在类成员函数上指定默认值的地方是哪里?
答案:类方法的默认值只能在类内的声明中指定(或在类外的首次声明中指定),而不能在类内和实现中都指定。否则会出现重新定义的错误。
class X { void func(int x = 5); // 可以在这里 }; void X::func(int x) { /* ... */ } // 但不能在这里!
故事 1
银行软件在编译阶段发生故障:部分重载函数与不同的默认值干扰了对所需函数的明确选择,调用在编译阶段是歧义的——结果是无法在手动修正之前构建发布版本。
故事 2
团队中流行一种风格,即将所有默认值移至实现中,而不是类的头文件中,然而对于某些类方法,这导致接口与实现之间的不一致——不同的 TU 看到不同的函数参数,导致奇怪的编译和运行时错误。
故事 3
在扩展公共库时,错误地添加了重载同一参数但默认值不同的函数。编译器在 API 调用时开始产生歧义,而用户则遇到过时的调用和破坏的二进制兼容性。