在C ++中放置默认参数值的位置?
默认参数值的地方是什么? 只是在函数定义,或声明,或两个地方?
默认参数值必须出现在声明中,因为这是调用者看到的唯一的东西。
编辑:正如其他人指出的,你可以有定义的论点,但我会build议编写所有的代码,如果这是不正确的。
你可以做,但从来都不是。 通常你在函数声明中做,然后所有的调用者都可以使用这个默认值。 但是, 您可以在函数定义中做到这一点,然后只有那些看到定义的人才能够使用默认值。
在声明(.h)中最有用的地方是所有的用户都会看到它。
有些人喜欢在实现中添加默认值(作为注释):
void foo(int x = 42, int y = 21); void foo(int x /* = 42 */, int y /* = 21 */) { ... }
但是,这意味着重复,并且会增加注释与代码不同步的可能性(比注释错误的注释更糟糕的是未注释的代码?)。
虽然这是一个“旧”的线程,我仍然想要添加以下内容:
我遇到了下一个案例:
- 在一个类的头文件中,我有
int SetI2cSlaveAddress( UCHAR addr, bool force );
- 在这个类的源文件中,我有
int CI2cHal::SetI2cSlaveAddress( UCHAR addr, bool force = false ) { ... }
正如我们所看到的,我已经把参数“force”的默认值放在类源文件中,而不是在类头文件中。
然后,我在派生类中使用该函数(派生类以公共方式inheritance基类):
SetI2cSlaveAddress( addr );
假设它将“force”参数视为“假”“理所当然”。
然而,编译器( 放在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()
提供一个或两个参数)!
所以,不仅对于一个类的用户来说,把一个参数的默认值放在头文件中是非常重要的,而且对于编译和function上的明智看来似乎是必须的!
如果这些函数是暴露的 – 非成员,公共或保护 – 则调用者应该知道它们,并且默认值必须在标题中。
如果这些函数是私有的,而且是非线性的,那么将默认值放在实现文件中是有意义的,因为这允许不会触发客户端重新编译的更改(对于在企业级中共享的低级库发展)。 也就是说,这肯定会让人感到困惑,并且在头文件中以更直观的方式呈现API时有文档价值,所以select妥协 – 尽pipe在没有任何令人信服的理由的情况下一致性是主要的。
声明通常是最“有用的”,但这取决于你想如何使用这个类。
两者都是无效的。
好问题…我发现编程人员通常使用声明来声明默认值。 我一直以一种方式(或警告)或另一种方式基于编译器
void testFunct(int nVal1, int nVal2=500); void testFunct(int nVal1, int nVal2) { using namespace std; cout << nVal1 << << nVal2 << endl; }
还有一点我没有find任何人提到:
如果你有虚拟方法,每个声明都可以有自己的默认值!
这取决于您所调用的接口将使用哪个值。
关于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
我强烈劝阻你这样使用它
你可以按照标准来做,但是要记住,如果你的代码在包含默认参数的定义之前看到没有默认参数的声明,那么就会出现编译错误。
例如,如果包含包含函数声明而没有默认参数列表的头文件,编译器会查找该原型文件,因为它不知道默认参数值,因此原型不匹配。
如果你在定义中使用默认参数的函数,那么包含该文件,但我不会build议。
再加一点。 具有默认参数的函数声明应该从右到左和从上到下 sorting 。
例如 ,在下面的函数声明中,如果您更改声明顺序,那么编译器会给您一个缺less的默认参数错误。 原因是编译器允许你在同一个作用域内把函数声明和默认参数分开,但是它应该是从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; }