.h和.cpp文件中的默认参数

时间:2013-02-15 19:41:01

标签: c++ oop header-files

编译器: g ++ 4.7.2

确定。所以我对.h.cpp文件中的默认参数感到困惑。许多地方(包括本网站)都提到默认参数只能添加到.h文件而不能添加到.cpp文件中。 但是,这段代码证明它是错误的:

test1.h

#pragma once

#include <iostream>
using namespace std;

class Class{
public:
    Class(int, int, int=1);
};

test1.cpp

#include "test1.h"

Class::Class(int a, int b=2, int c)
{
    cout<<a<<" "<<b<<" "<<c<<endl;
}

int main()
{
    Class a(1);
    return 0;
}

现在,根据我测试的内容,可以将默认参数添加到.cpp个文件中。但是,存在以下限制:

  1. .cpp.h文件中的默认参数不应该 交叠。即Class(a, b, c=1)(在.h文件中)和 Class::Class(a,b,c=2)(在.cpp文件中)无效。

    一旦默认参数已经存在,这是一个众所周知的规则 补充说,之后声明的所有变量也必须包含 默认值。让我们称之为 defpara 规则。现在,

  2. 函数声明(.h文件)中声明的变量应该是 遵守 defpara 规则,即Class(a, b=2, c)(在.h文件中)是 无论在.cpp文件中声明什么都无效。

  3. 如果考虑具有默认值的变量(作为 它会在.h.cpp文件中的默认值的交集 按照 defpara 规则进行操作。即Class(a, b, c=1)(在.h文件中)和 Class::Class(a,b=2,c)(在.cpp文件中)有效。但是Class(a, b, c=1)(在.h文件中)和Class::Class(a=2,b,c)(在.cpp文件中)是 无效。

  4. 所以....我是对的,错了???

4 个答案:

答案 0 :(得分:57)

如果函数在头文件中声明,则默认值应始终放在头文件中。

这是因为编译器将使用头文件用于使用您的类的所有编译单元[除非您是“顽皮”并且不要在任何地方使用头文件]。

由于编译器在编译CALLS函数的代码(在本例中为构造函数)时添加了默认参数,因此.cpp文件中的默认值无关紧要。

当然,在这种情况下,头文件只有一个“用户”,并且只有一个调用构造函数的位置。但是.cpp文件中的默认值通常是错误的[除非它是本地函数]。

如果你“混合”默认值,你会得到非常“有趣”的错误 - 例如如果你的.cpp有一个默认值,而headefile是另一个默认值。如果你真的很熟练,你甚至可以让编译器为函数的不同调用生成不同的默认值,如果代码依赖于默认值是某个特定值,这几乎肯定会导致一些头痛。并且不要试图将标题中的默认值复制到.cpp文件“只是为了让它更容易看到”。如果有人更改了默认值,那么几乎可以肯定要么两个地方都不会改变,可能更糟糕的是:更改错误的默认值,因此它不会按预期执行。

答案 1 :(得分:22)

这只能起作用,因为你的main函数也在你的test.cpp文件中,因此它会看到你的类实现中指定的默认参数。如果将main函数放在仅包含test.h的单独文件中,则此代码将无法编译。

另一种看待它的方法是,当其他一些包括test.h时,所有代码看到的都是test.h中声明的内容,因此不会使用放在别处的默认参数。

答案 2 :(得分:6)

.h vs. .cpp是一只红鲱鱼。规则是默认参数可以在函数声明和函数定义中使用。您不能重新定义默认参数,甚至不能重新定义相同的值。所以这不合法:

void f(int, int = 3);
void f(int, int = 3); // error: redefinition of default argument

但是,后续声明可以添加默认参数:

void f(int, int = 3);
void f(int = 4, int = 3);
f(); // calls f(4, 3);

此外,在调用函数的任何位置,都可以使用在该点看到的默认参数:

void f(int, int =3);
f(1); // calls f(1, 3);
void f(int = 4, int = 3);
f(1); // calls f(1, 3);
f();  // calls f(4, 3);

在原始示例中,.h文件定义了一个默认参数,使用该标头的任何转换单元都可以使用该默认参数:

Class c3(1, 2, 3);
Class c2(1, 2);

此外,.cpp文件定义了一个额外的默认参数,因此在该声明之后,可以使用一个,两个或三个参数调用构造函数:

Class c3(1, 2, 3);
class c2(1, 2);
class c1(1);

答案 3 :(得分:2)

在C ++中没有用于定义文件的默认参数 - 它只存在于声明中。

编译器看到的函数缺少后面的参数。如果这些是默认的,它可以填充空白来构造目标代码来调用函数,就像函数调用具有那些参数一样。

PS:第38项/ Scott Myers / Effective C ++ - 永远不要重新定义继承的默认参数值。