C++ 构造函数的默认参数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/187640/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 13:33:20  来源:igfitidea点击:

Default parameters with C++ constructors

c++constructorcoding-styleoverloading

提问by Rob

Is it good practice to have a class constructor that uses default parameters, or should I use separate overloaded constructors? For example:

使用默认参数的类构造函数是一种好习惯,还是应该使用单独的重载构造函数?例如:

// Use this...
class foo  
{
private:
    std::string name_;
    unsigned int age_;
public:
    foo(const std::string& name = "", const unsigned int age = 0) :
        name_(name),
        age_(age)
    {
        ...
    }
};

// Or this?
class foo  
{
private:
    std::string name_;
    unsigned int age_;
public:
    foo() :
    name_(""),
    age_(0)
{
}

foo(const std::string& name, const unsigned int age) :
        name_(name),
        age_(age)
    {
        ...
    }
};

Either version seems to work, e.g.:

任何一个版本似乎都有效,例如:

foo f1;
foo f2("Name", 30);

Which style do you prefer or recommend and why?

您更喜欢或推荐哪种风格,为什么?

采纳答案by luke

Definitely a matter of style. I prefer constructors with default parameters, so long as the parameters make sense. Classes in the standard use them as well, which speaks in their favor.

绝对是风格问题。我更喜欢带有默认参数的构造函数,只要参数有意义。标准中的类也使用它们,这对它们有利。

One thing to watch out for is if you have defaults for all but one parameter, your class can be implicitly converted from that parameter type. Check out this threadfor more info.

需要注意的一件事是,如果除了一个参数之外的所有参数都有默认值,则您的类可以从该参数类型隐式转换。查看此线程以获取更多信息。

回答by Sam Stokes

I'd go with the default arguments, especially since C++ doesn't let you chain constructors (so you end up having to duplicate the initialiser list, and possibly more, for each overload).

我会使用默认参数,特别是因为 C++ 不允许您链接构造函数(因此您最终不得不为每个重载复制初始化列表,可能还有更多)。

That said, there are some gotchas with default arguments, including the fact that constants may be inlined (and thereby become part of your class' binary interface). Another to watch out for is that adding default arguments can turn an explicit multi-argument constructor into an implicit one-argument constructor:

也就是说,有一些带有默认参数的陷阱,包括常量可能被内联(从而成为类的二进制接口的一部分)这一事实。另一个需要注意的是,添加默认参数可以将显式多参数构造函数变成隐式单参数构造函数:

class Vehicle {
public:
  Vehicle(int wheels, std::string name = "Mini");
};

Vehicle x = 5;  // this compiles just fine... did you really want it to?

回答by paercebal

This discussion apply both to constructors, but also methods and functions.

这个讨论既适用于构造函数,也适用于方法和函数。

Using default parameters?

使用默认参数?

The good thing is that you won't need to overload constructors/methods/functions for each case:

好处是你不需要为每种情况重载构造函数/方法/函数:

// Header
void doSomething(int i = 25) ;

// Source
void doSomething(int i)
{
   // Do something with i
}

The bad thing is that you must declare your default in the header, so you have an hidden dependancy: Like when you change the code of an inlined function, if you change the default value in your header, you'll need to recompile all sources using this header to be sure they will use the new default.

不好的是你必须在头文件中声明你的默认值,所以你有一个隐藏的依赖:就像你改变内联函数的代码一样,如果你改变了头文件中的默认值,你需要重新编译所有源代码使用此标头以确保他们将使用新的默认值。

If you don't, the sources will still use the old default value.

如果不这样做,源仍将使用旧的默认值。

using overloaded constructors/methods/functions?

使用重载的构造函数/方法/函数?

The good thing is that if your functions are not inlined, you then control the default value in the source by choosing how one function will behave. For example:

好消息是,如果您的函数没有内联,那么您可以通过选择一个函数的行为方式来控制源中的默认值。例如:

// Header
void doSomething() ;
void doSomething(int i) ;

// Source

void doSomething()
{
   doSomething(25) ;
}

void doSomething(int i)
{
   // Do something with i
}

The problem is that you have to maintain multiple constructors/methods/functions, and their forwardings.

问题是您必须维护多个构造函数/方法/函数及其转发。

回答by Paul Nathan

In my experience, default parameters seem cool at the time and make my laziness factor happy, but then down the road I'm using the class and I am surprised when the default kicks in. So I don't really think it's a good idea; better to have a className::className() and then a className::init(arglist). Just for that maintainability edge.

根据我的经验,默认参数在当时看起来很酷,让我的懒惰因素很高兴,但后来我正在使用这个类,当默认值生效时我很惊讶。所以我真的不认为这是一个好主意; 最好有一个 className::className() 然后一个 className::init( arglist)。只是为了那个可维护性优势。

回答by Richard Corden

Sam'sanswer gives the reason that default arguments are preferable for constructors rather than overloading. I just want to add that C++-0x will allow delegationfrom one constructor to another, thereby removing the need for defaults.

Sam 的回答给出了默认参数更适合构造函数而不是重载的原因。我只想补充一点,C++-0x 将允许从一个构造函数委托给另一个构造函数,从而消除对默认值的需要。

回答by Rodney Schuler

Either approach works. But if you have a long list of optional parameters make a default constructor and then have your set function return a reference to this. Then chain the settors.

这两种方法都有效。但是,如果您有一长串可选参数,请创建一个默认构造函数,然后让您的 set 函数返回对此的引用。然后链接设置器。

class Thingy2
{
public:
    enum Color{red,gree,blue};
    Thingy2();

    Thingy2 & color(Color);
    Color color()const;

    Thingy2 & length(double);
    double length()const;
    Thingy2 & width(double);
    double width()const;
    Thingy2 & height(double);
    double height()const;

    Thingy2 & rotationX(double);
    double rotationX()const;
    Thingy2 & rotatationY(double);
    double rotatationY()const;
    Thingy2 & rotationZ(double);
    double rotationZ()const;
}

main()
{
    // gets default rotations
    Thingy2 * foo=new Thingy2().color(ret)
        .length(1).width(4).height(9)
    // gets default color and sizes
    Thingy2 * bar=new Thingy2()
        .rotationX(0.0).rotationY(PI),rotationZ(0.5*PI);
    // everything specified.
    Thingy2 * thing=new Thingy2().color(ret)
        .length(1).width(4).height(9)
        .rotationX(0.0).rotationY(PI),rotationZ(0.5*PI);
}

Now when constructing the objects you can pick an choose which properties to override and which ones you have set are explicitly named. Much more readable :)

现在,在构建对象时,您可以选择要覆盖的属性以及已设置的显式命名的属性。更具可读性:)

Also, you no longer have to remember the order of the arguments to the constructor.

此外,您不再需要记住构造函数的参数顺序。

回答by Nik Reiman

If creating constructors with arguments is bad (as many would argue), then making them with default arguments is even worse. I've recently started to come around to the opinion that ctor arguments are bad, because your ctor logic should be as minimal as possible. How do you deal with error handling in the ctor, should somebody pass in an argument that doesn't make any sense? You can either throw an exception, which is bad news unless all of your callers are prepared to wrap any "new" calls inside of try blocks, or setting some "is-initialized" member variable, which is kind of a dirty hack.

如果创建带有参数的构造函数很糟糕(正如许多人会争论的那样),那么使用默认参数创建它们就更糟了。我最近开始接受 ctor 参数不好的观点,因为你的 ctor 逻辑应该尽可能小。如果有人传入一个没有任何意义的参数,你如何处理 ctor 中的错误处理?你可以抛出一个异常,这是个坏消息,除非你的所有调用者都准备在 try 块内包装任何“新”调用,或者设置一些“is-initialized”成员变量,这是一种肮脏的黑客。

Therefore, the only way to make sure that the arguments passed into the initialization stage of your object is to set up a separate initialize() method where you can check the return code.

因此,确保参数传递到对象初始化阶段的唯一方法是设置一个单独的 initialize() 方法,您可以在其中检查返回代码。

The use of default arguments is bad for two reasons; first of all, if you want to add another argument to the ctor, then you are stuck putting it at the beginning and changing the entire API. Furthermore, most programmers are accustomed to figuring out an API by the way that it's used in practice -- this is especiallytrue for non-public API's used inside of an organization where formal documentation may not exist. When other programmers see that the majority of the calls don't contain any arguments, they will do the same, remaining blissfully unaware of the default behavior your default arguments impose on them.

使用默认参数不好有两个原因;首先,如果您想向 ctor 添加另一个参数,那么您将被困在开头并更改整个 API。此外,大多数程序员习惯于通过实际使用的方式来确定 API——对于在可能不存在正式文档的组织内部使用的非公共 API尤其如此。当其他程序员看到大多数调用不包含任何参数时,他们会做同样的事情,仍然幸福地不知道默认参数强加给他们的默认行为。

Also, it's worth noting that the google C++ style guideshuns both ctor arguments (unless absolutely necessary), and default arguments to functions or methods.

此外,值得注意的是,谷歌 C++ 风格指南避开了 ctor 参数(除非绝对必要)和函数或方法的默认参数

回答by peter

One more thing to consider is whether or not the class could be used in an array:

要考虑的另一件事是该类是否可以在数组中使用:

foo bar[400];

In this scenario, there is no advantage to using the default parameter.

在这种情况下,使用默认参数没有任何好处。

This would certainly NOT work:

这肯定行不通:

foo bar("david", 34)[400]; // NOPE

回答by Yang Lu

Mostly personal choice. However, overload can do anything default parameter can do, but notvice versa.

主要是个人选择。然而,过载可以做任何默认参数可以做,但不是反之亦然。

Example:

例子:

You can use overload to write A(int x, foo& a) and A(int x), but you cannot use default parameter to write A(int x, foo& = null).

您可以使用重载来编写 A(int x, foo& a) 和 A(int x),但不能使用默认参数来编写 A(int x, foo& = null)。

The general rule is to use whatever makes sense and makes the code more readable.

一般规则是使用任何有意义的东西并使代码更具可读性。

回答by James Curran

I would go with the default parameters, for this reason: Your example assumes that ctor parameters directly correspond to member variables. But what if that is not the case, and you have to process the parameters before the object is initialize. Having one common ctor would be the best way to go.

由于这个原因,我会使用默认参数:您的示例假定 ctor 参数直接对应于成员变量。但如果情况并非如此,并且您必须在对象初始化之前处理参数呢?拥有一个共同的 ctor 将是最好的方法。