7.4 默认参数

在Stash3.h中,比较了Stash()的两个构造函数,它们似乎并没有多大不同,对不对?事实上,第一个构造函数只不过是第二个的一个特例—它的初始size为零。在这种情况下创建和管理同一函数的两个不同版本实在是浪费精力。

C++通过默认参数(default argument)提供了一种补救方法。默认参数是在函数声明时就已给定的一个值,如果在调用函数时没有指定这一参数的值,编译器就会自动地插上这个值。在Stash的例子中,可以把两个函数:

7.4 默认参数 - 图1

用一个函数声明来代替:

7.4 默认参数 - 图2

这样,Stash(int)定义就简化掉了—所需要的是一个单一的Stash(int, int)定义。现在这两个对象的定义:

7.4 默认参数 - 图3

将会产生完全相同的结果。它们将调用同一个构造函数。但对于A,它的第二个参数是由编译器在看到第一个参数是int而且没有第二个参数时自动加上去的。编译器能看到默认参数,所以它知道应该允许这样的调用,就好像它提供第二个参数一样,而这第二个参数值就是已经告知编译器的默认参数。

默认参数同函数重载一样,给程序员提供了很多方便,它们都使我们可以在不同的场合下使用同一函数名字。不同之处是,利用默认参数,当我们不想亲手提供这些值时,由编译器提供一个默认参数。上面的那个例子就是用默认参数而不用函数重载的一个很好的例子。否则,我们必然面临有几乎同样含义、同样操作的两个或更多的函数。当然,如果函数之间的行为差异较大,用默认参数就不合适了(对于这个问题,我们想知道两个差异较大的函数是否应当有相同的名字)。

在使用默认参数时必须记住两条规则。第一,只有参数列表的后部参数才是可默认的,也就是说,不可以在一个默认参数后面又跟一个非默认的参数。第二,一旦在一个函数调用中开始使用默认参数,那么这个参数后面的所有参数都必须是默认的(这可以从第一条中导出)。

默认参数只能放在函数声明中,通常在一个头文件中。编译器必须在使用该函数之前知道默认值。有时人们为了阅读方便在函数定义处放上一些默认的注释值。如:

7.4 默认参数 - 图4

7.4.1 占位符参数

函数声明时,参数可以没有标识符,当这些不带标识符的参数用做默认参数时,看起来很有意思。可以这样声明:

7.4 默认参数 - 图5

在C++中,在函数定义时,并不一定需要标识符,如:

7.4 默认参数 - 图6

在函数体中,x和flt可以被引用,但中间的这个参数值则不行,因为它没有名字。调用还必须为这个占位符(placeholder)提供一个值,有f(1)或f(1,2,3.0)。这种语法允许把一个参数用做占位符而不去用它。其目的在于以后可以修改函数定义而不需要修改所有的函数调用。当然,用一个有名字的参数也能达到同样的目的,但如果定义的这个参数在函数体内没有使用它,多数编译器会给出一条警告信息,并认为犯了一个逻辑错误。用这种没有名字的参数,我们就可以防止这种警告产生。

更重要的是,如果开始用了一个函数参数,而后来发现不需要用它,可以将它去掉而不会产生警告错误,而且不需要改动那些调用该函数以前版本的程序代码。