游戏开发工具

到底在声明中还是定义中指定默认参数

上节的例子中,我们在函数定义处指定了默认参数。除了函数定义,你也可以在函数声明处指定默认参数。不过当出现函数声明时情况会变得稍微复杂,有时候你可以在声明处和定义处同时指定默认参数,有时候你只能在声明处指定,请看下面的例子(示例1):

#include <iostream>
using namespace std;

void func(int a, int b = 10, int c = 36);

int main()
{
    func(99);
    return 0;
}

void func(int a, int b = 10, int c = 36)
{
    cout<<a<<", "<<b<<", "<<c<<endl;
}

这段代码在编译时会报错,错误信息表明不能在函数定义和函数声明中同时指定默认参数。对代码稍作修改,将 func() 函数的定义放到其他源文件中,如下所示(示例2)。

main.cpp 代码:

#include <iostream>
using namespace std;

void func(int a, int b = 10, int c = 36);

int main()
{
    func(99);
    return 0;
}

module.cpp 代码:

#include <iostream>
using namespace std;

void func(int a, int b = 10, int c = 36)
{
    cout<<a<<", "<<b<<", "<<c<<endl;
}

运行结果:

99, 10, 36


修改后的代码是可以编译通过的,这有点让人摸不着头脑,为什么将 func() 的定义放到其他源文件中就不一样了呢?

如果读者对多文件编程不了解,请阅读《C语言多文件编程》,C++ 在多文件编程方面仍然在使用C语言的规则。

这是因为C++ 规定,在给定的作用域中只能指定一次默认参数。

对于示例1,func() 的定义和声明位于同一个源文件,它们的作用域也都是整个源文件,这样就导致在同一个文件作用域中指定了两次默认参数,违反了 C++ 的规定。

对于示例2,func() 的声明位于main.cpp,作用域也是main.cpp,而 func() 的定义位于module.cpp,作用域也是module.cpp,func() 的声明和定义位于不同的作用域,相互之间不影响。

C语言有四种作用域,分别是函数原型作用域、局部作用域(函数作用域)、块作用域、文件作用域(全局作用域),C++ 也有这几种作用域。

继续对代码进行修改,将 func() 定义处 b、c 的默认值分别设置为 5、57,而声明处 b、c 的默认值不变,依然为 10、36。编译并运行程序,发现输出结果与上面一样,这说明编译器使用的是当前作用域中的默认参数。站在编译器的角度看,它不管当前作用域中是函数声明还是函数定义,只要有默认参数就可以使用。

多次声明同一函数

在多文件编程时,我们通常的做法是将函数声明放在头文件中,并且一个函数只声明一次,但是多次声明同一函数也是合法的。

不过有一点需要注意,在给定的作用域中一个形参只能被赋予一次默认参数。换句话说,函数的后续声明只能为之前那些没有默认值的形参添加默认值,而且该形参右侧的所有形参必须都有默认值。

为了说明问题,我们不妨对 main.cpp 中的代码稍作修改:

#include <iostream>
using namespace std;

//多次声明同一个函数
void func(int a, int b, int c = 36);
void func(int a, int b = 5, int c);

int main()
{
    func(99);
    return 0;
}

这种声明方式是正确的。第一次声明时为 c 指定了默认值,第二次声明时为 b 指定了默认值;第二次声明是添加默认参数。需要提醒的是,第二次声明时不能再次给 c 指定默认参数,否则就是重复声明同一个默认参数。