本节书摘来自异步社区出版社《C++覆辙录》一书中的第1章,第1.4节,作者: 【美】Stephen C. Dewhurst(史蒂芬 C. 杜赫斯特),更多章节内容可以访问云栖社区“异步社区”公众号查看。
1.4:未能区分函数重载和形参默认值
函数重载和形参默认值之间其实并无干系。不过,这两个独立的语言特征有时会被混淆,因为它们会模塑出语法上非常相像的函数用法接口。当然,看似一样的接口其背后的抽象意义却大相径庭:
class C1 {
public:
void f1( int arg = 0 );
// ...
};```
// ...
C1 a;
a.f1(0);
a.f1();`
型别C1
的设计者决定给予函数f1()
一个形参的默认值。这样一来,C1
的使用者就有了两个选择:要么显式地给函数f1()
一个实参,要么通过不指定任何实参的方式隐式地给函数f1()
一个实参0。所以,上述两个函数调用产生的动作序列12是完全相同的。
class C2 {
public:
void f2();
void f2( int );
// ...
};```
// ...
C2 a;
a.f2(0);
a.f2();`
型别C2的实现则有很大不同。其使用者的选择是根据给予的实参数目调用两个虽然名字都叫f2()
,却是完全不同的函数中的某一个。在我们早先那个C1
型别的例子里,两个函数调用产生的动作序列是完全相同的,但在这个例子里它们产生的却是完全不同的动作序列了。这是因为两个函数调用的结果是调用了不同的函数。
通过对成员函数C1::f1()
和C2:f2()
取址,我们就拿到了有关这两种接口之间最本质的不同点的直接证据:
1.jpg gotcha04/c12.cpp
void (C1::*pmf)() = &C1::f1; //错误!
void (C2::*pmf)() = &C2::f2;```
我们实现C2型别的方法决定了指涉到成员函数的指针`pmf`指涉到了没有带任何形参的那个`f2()`函数。因为`pmf`是个指涉到没有带任何形参的成员函数的指针,编译器能够正确地选择第一个`f2()`作为它应该指涉到的函数。而对于`C1`型别来说,我们将收到编译期错误,因为唯一的名叫`f1()`的成员函数带有一个int型别的形参13。