在C ++中放置默认参数值的位置?

时间:2011-02-14 06:39:02

标签: c++ default-arguments

默认参数值的位置是什么?只是在函数定义,声明或两个地方?

10 个答案:

答案 0 :(得分:288)

默认参数值必须出现在声明中,因为这是调用者看到的唯一内容。

编辑:正如其他人指出的那样,可以在定义上有参数,但我建议将所有代码编写为不正确。

答案 1 :(得分:91)

你可以做任何一种,但绝不能同时做到。通常在函数声明中执行它,然后所有调用者都可以使用该默认值。但是you can do that at function definition instead然后只有那些看到定义的人才能使用默认值。

答案 2 :(得分:77)

最有用的地方是声明(.h),以便所有用户都能看到它。

有些人喜欢在实现中添加默认值(作为注释):

void foo(int x = 42,
         int y = 21);

void foo(int x /* = 42 */,
         int y /* = 21 */)
{
   ...
}

然而,这意味着重复,并且会增加注释与代码不同步的可能性(比未注释的代码更糟糕的是?带有误导性评论的代码!)。

答案 3 :(得分:37)

虽然这是一个“旧”主题,但我仍想在其中添加以下内容:

我经历了下一个案例:

  • 在课程的头文件中,我有
int SetI2cSlaveAddress( UCHAR addr, bool force );
  • 在该类的源文件中,我有
int CI2cHal::SetI2cSlaveAddress( UCHAR addr, bool force = false )
{
   ...
}

可以看出,我已将参数“force”的默认值放在类源文件中,而不是在类头文件中。

然后我在派生类中使用了该函数,如下所示(派生类以公共方式继承基类):

  

SetI2cSlaveAddress( addr );

假设它将“force”参数视为“false”'被授予'。

然而,编译器( 放入c ++ 11模式 )抱怨并给了我以下编译器错误:

/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp: In member function 'void CMax6956Io::Init(unsigned char, unsigned char, unsigned int)':
/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp:26:30: error: no matching function for call to 'CMax6956Io::SetI2cSlaveAddress(unsigned char&)'
/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp:26:30: note: candidate is:
In file included from /home/geertvc/mystuff/domoproject/lib/i2cdevs/../../include/i2cdevs/max6956io.h:35:0,
                 from /home/geertvc/mystuff/domoproject/lib/i2cdevs/max6956io.cpp:1:
/home/.../mystuff/domoproject/lib/i2cdevs/../../include/i2chal/i2chal.h:65:9: note: int CI2cHal::SetI2cSlaveAddress(unsigned char, bool)
/home/.../mystuff/domoproject/lib/i2cdevs/../../include/i2chal/i2chal.h:65:9: note:   candidate expects 2 arguments, 1 provided
make[2]: *** [lib/i2cdevs/CMakeFiles/i2cdevs.dir/max6956io.cpp.o] Error 1
make[1]: *** [lib/i2cdevs/CMakeFiles/i2cdevs.dir/all] Error 2
make: *** [all] Error 2

但是当我在基类的 标题 文件中添加默认参数时:

  

int SetI2cSlaveAddress( UCHAR addr, bool force = false );

并将其从基类的源文件中删除:

  

int CI2cHal::SetI2cSlaveAddress( UCHAR addr, bool force )

然后编译器很开心,所有代码都按预期工作(我可以给函数SetI2cSlaveAddress()提供一个或两个参数)!

因此,不仅对于类的用户而言,将参数的默认值放在头文件中也很重要,同时编译和功能明智,这显然是必须的!

答案 4 :(得分:12)

如果函数被公开 - 非成员,公共或受保护 - 那么调用者应该知道它们,并且默认值必须在标题中。

如果函数是私有的和不在线的,那么将默认值放在实现文件中是有意义的,因为这允许更改不会触发客户端重新编译(对于共享的低级库有时会出现严重问题)在企业规模发展中)。也就是说,它肯定会让人感到困惑,并且在标题中以更直观的方式呈现API有文档价值,所以选择你的妥协 - 尽管在任何方式都没有令人信服的理由时,一致性是主要的。

答案 5 :(得分:10)

声明通常是最“有用的”,但这取决于你想如何使用这个类。

两者都无效。

答案 6 :(得分:10)

好问题...... 我发现编码器通常使用声明来声明默认值。基于编译器

,我一直被一种方式(或警告)或另一种方式所控制
void testFunct(int nVal1, int nVal2=500);
void testFunct(int nVal1, int nVal2)
{
    using namespace std;
    cout << nVal1 << << nVal2 << endl;
}

答案 7 :(得分:9)

还有一点我没有发现任何人提到过:

如果你有虚方法,每个声明都可以有自己的默认值!

这取决于您调用的接口将使用哪个值。

ideone

上的示例
struct iface
{
    virtual void test(int a = 0) { std::cout << a; }
};

struct impl : public iface
{
    virtual void test(int a = 5) override { std::cout << a; }
};

int main()
{
    impl d;
    d.test();
    iface* a = &d;
    a->test();
}

打印50

我强烈反对您不要像这样使用

答案 8 :(得分:3)

您可以使用(根据标准),但请记住,如果您的代码在包含默认参数的定义之前看到没有默认参数的声明,则可能会出现编译错误。

例如,如果包含包含函数声明的头而没有默认参数列表,那么编译器将查找该原型,因为它不知道您的默认参数值,因此原型将不匹配。

如果你在定义中放置带有默认参数的函数,那么请包含该文件,但我不建议这样做。

答案 9 :(得分:3)

再加一点。带有默认参数的函数声明应从右到左排序从上到下排序

例如在下面的函数声明中,如果更改声明顺序,则编译器会为您提供缺少的默认参数错误。编译器允许您在同一范围内将函数声明与默认参数分开的原因,但它应该是从RIGHT到LEFT(默认参数)和从TOP到BOTTOM(函数声明默认参数的顺序)的顺序。

//declaration
void function(char const *msg, bool three, bool two, bool one = false);
void function(char const *msg, bool three = true, bool two, bool one); // Error 
void function(char const *msg, bool three, bool two = true, bool one); // OK
//void function(char const *msg, bool three = true, bool two, bool one); // OK

int main() {
    function("Using only one Default Argument", false, true);
    function("Using Two Default Arguments", false);
    function("Using Three Default Arguments");
    return 0;
}

//definition
void function(char const *msg, bool three, bool two, bool one ) {
    std::cout<<msg<<" "<<three<<" "<<two<<" "<<one<<std::endl;
}