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

default parameters in .h and .cpp files

本文关键字:默认 参数 文件 cpp      更新时间:2023-10-16

编译器: g++4.7.2

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

测试1.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文件中)无效的

所以。。。。我是对的,错的???

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

这是因为编译器将为所有使用类的编译单元使用头文件[除非你很"顽皮",不要在它应该去的地方使用头文件]。

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

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

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

这只是因为您的主函数也在test.cpp文件中,所以它会看到在类的实现中指定的默认参数。如果将main函数放在只包含test.h的单独文件中,则不会编译此代码。

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

.h与.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);

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

发生的情况是编译器看到一个缺少后一个参数的函数。如果这些是默认的,它可以填充空格来构造调用函数的对象代码,就像函数调用有这些参数一样。

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