我可以在 C++ 中从另一个构造函数调用构造函数(做构造函数链接)吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/308276/
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 14:31:06  来源:igfitidea点击:

Can I call a constructor from another constructor (do constructor chaining) in C++?

c++constructor

提问by Stormenet

As a C#developer I'm used to running through constructors:

作为C#开发人员,我习惯于运行构造函数:

class Test {
    public Test() {
        DoSomething();
    }

    public Test(int count) : this() {
        DoSomethingWithCount(count);
    }

    public Test(int count, string name) : this(count) {
        DoSomethingWithName(name);
    }
}

Is there a way to do this in C++?

有没有办法在 C++ 中做到这一点?

I tried calling the Class name and using the 'this' keyword, but both fail.

我尝试调用类名并使用“this”关键字,但都失败了。

回答by JohnIdol

C++11: Yes!

C++11:是的!

C++11 and onwards has this same feature (called delegating constructors).

C++11 及以后的版本具有相同的特性(称为委托构造函数)。

The syntax is slightly different from C#:

语法与 C# 略有不同:

class Foo {
public: 
  Foo(char x, int y) {}
  Foo(int y) : Foo('a', y) {}
};

C++03: No

C++03:没有

Unfortunately, there's no way to do this in C++03, but there are two ways of simulating this:

不幸的是,在 C++03 中没有办法做到这一点,但有两种方法可以模拟这一点:

  1. You can combine two (or more) constructors via default parameters:

    class Foo {
    public:
      Foo(char x, int y=0);  // combines two constructors (char) and (char, int)
      // ...
    };
    
  2. Use an init method to share common code:

    class Foo {
    public:
      Foo(char x);
      Foo(char x, int y);
      // ...
    private:
      void init(char x, int y);
    };
    
    Foo::Foo(char x)
    {
      init(x, int(x) + 7);
      // ...
    }
    
    Foo::Foo(char x, int y)
    {
      init(x, y);
      // ...
    }
    
    void Foo::init(char x, int y)
    {
      // ...
    }
    
  1. 您可以通过默认参数组合两个(或多个)构造函数:

    class Foo {
    public:
      Foo(char x, int y=0);  // combines two constructors (char) and (char, int)
      // ...
    };
    
  2. 使用 init 方法共享公共代码:

    class Foo {
    public:
      Foo(char x);
      Foo(char x, int y);
      // ...
    private:
      void init(char x, int y);
    };
    
    Foo::Foo(char x)
    {
      init(x, int(x) + 7);
      // ...
    }
    
    Foo::Foo(char x, int y)
    {
      init(x, y);
      // ...
    }
    
    void Foo::init(char x, int y)
    {
      // ...
    }
    

See the C++FAQ entryfor reference.

请参阅C++FAQ 条目以供参考。

回答by Cyrille Ka

No, you can't call one constructor from another in C++03 (called a delegating constructor).

不,您不能在 C++03 中从另一个构造函数调用一个构造函数(称为委托构造函数)。

This changed in C++11 (aka C++0x), which added support for the following syntax:
(example taken from Wikipedia)

这在 C++11(又名 C++0x)中发生了变化,它增加了对以下语法的支持:(
示例取自Wikipedia

class SomeType
{
  int number;

public:
  SomeType(int newNumber) : number(newNumber) {}
  SomeType() : SomeType(42) {}
};

回答by ohlemacher

I believe you can call a constructor from a constructor. It will compile and run. I recently saw someone do this and it ran on both Windows and Linux.

我相信您可以从构造函数调用构造函数。它将编译并运行。我最近看到有人这样做,它在 Windows 和 Linux 上都运行。

It just doesn't do what you want. The inner constructor will construct a temporary local object which gets deleted once the outer constructor returns. They would have to be different constructors as well or you would create a recursive call.

它只是不做你想要的。内部构造函数将构造一个临时本地对象,一旦外部构造函数返回,该对象就会被删除。它们也必须是不同的构造函数,否则您将创建一个递归调用。

Ref: https://isocpp.org/wiki/faq/ctors#init-methods

参考:https: //isocpp.org/wiki/faq/ctors#init-methods

回答by kchoose2

It is worth pointing out that you cancall the constructor of a parent class in your constructor e.g.:

值得指出的是,您可以在构造函数中调用父类的构造函数,例如:

class A { /* ... */ };

class B : public A
{
    B() : A()
    {
        // ...
    }
};

But, no, you can't call another constructor of the same class.

但是,不,您不能调用同一类的另一个构造函数。

回答by Ben L

In C++11, a constructor can call another constructor overload:

C++11 中构造函数可以调用另一个构造函数重载

class Foo  {
     int d;         
public:
    Foo  (int i) : d(i) {}
    Foo  () : Foo(42) {} //New to C++11
};

Additionally, members can be initialized like this as well.

此外,成员也可以这样初始化。

class Foo  {
     int d = 5;         
public:
    Foo  (int i) : d(i) {}
};

This should eliminate the need to create the initialization helper method. And it is still recommended not calling any virtual functions in the constructors or destructors to avoid using any members that might not be initialized.

这应该消除了创建初始化辅助方法的需要。并且仍然建议不要在构造函数或析构函数中调用任何虚函数,以避免使用任何可能未初始化的成员。

回答by lyngvi

If you want to be evil, you can use the in-place "new" operator:

如果你想作恶,你可以使用就地“new”操作符:

class Foo() {
    Foo() { /* default constructor deliciousness */ }
    Foo(Bar myParam) {
      new (this) Foo();
      /* bar your param all night long */
    } 
};

Seems to work for me.

似乎对我有用。

edit

编辑

As @ElvedinHamzagic points out, if Foo contained an object which allocated memory, that object might not be freed. This complicates things further.

正如@ElvedinHamzagic 指出的那样,如果 Foo 包含一个分配了内存的对象,则该对象可能不会被释放。这使事情进一步复杂化。

A more general example:

一个更一般的例子:

class Foo() {
private:
  std::vector<int> Stuff;
public:
    Foo()
      : Stuff(42)
    {
      /* default constructor deliciousness */
    }

    Foo(Bar myParam)
    {
      this->~Foo();
      new (this) Foo();
      /* bar your param all night long */
    } 
};

Looks a bit less elegant, for sure. @JohnIdol's solution is much better.

当然,看起来不那么优雅。@JohnIdol 的解决方案要好得多。

回答by unwind

No, in C++ you cannot call a constructor from a constructor. What you can do, as warren pointed out, is:

不,在 C++ 中,您不能从构造函数调用构造函数。正如沃伦指出的那样,你可以做的是:

  • Overload the constructor, using different signatures
  • Use default values on arguments, to make a "simpler" version available
  • 使用不同的签名重载构造函数
  • 对参数使用默认值,使“更简单”的版本可用

Note that in the first case, you cannot reduce code duplication by calling one constructor from another. You can of course have a separate, private/protected, method that does all the initialization, and let the constructor mainly deal with argument handling.

请注意,在第一种情况下,您不能通过从另一个构造函数调用一个构造函数来减少代码重复。你当然可以有一个单独的、私有/受保护的方法来完成所有的初始化,让构造函数主要处理参数处理。

回答by unwind

Simply put, you cannot before C++11.

简单地说,你不能在 C++11 之前。

C++11 introduces delegating constructors:

C++11 引入了委托构造函数

Delegating constructor

If the name of the class itself appears as class-or-identifier in the member initializer list, then the list must consist of that one member initializer only; such constructor is known as the delegating constructor, and the constructor selected by the only member of the initializer list is the target constructor

In this case, the target constructor is selected by overload resolution and executed first, then the control returns to the delegating constructor and its body is executed.

Delegating constructors cannot be recursive.

class Foo {
public: 
  Foo(char x, int y) {}
  Foo(int y) : Foo('a', y) {} // Foo(int) delegates to Foo(char,int)
};

委托构造函数

如果类名本身在成员初始值设定项列表中显示为类或标识符,则该列表必须仅包含该成员初始值设定项;这样的构造函数被称为委托构造函数,并且初始化列表中唯一的成员选择的构造函数是目标构造函数

在这种情况下,目标构造函数通过重载决议选择并首先执行,然后控制返回到委托构造函数并执行其主体。

委托构造函数不能递归。

class Foo {
public: 
  Foo(char x, int y) {}
  Foo(int y) : Foo('a', y) {} // Foo(int) delegates to Foo(char,int)
};

Note that a delegating constructor is an all-or-nothing proposal; if a constructor delegates to another constructor, the calling constructor isn't allowed to have any other members in its initialization list. This makes sense if you think about initializing const/reference members once, and only once.

请注意,委托构造函数是一个全有或全无的提议;如果构造函数委托给另一个构造函数,则不允许调用构造函数在其初始化列表中包含任何其他成员。如果您考虑将 const/reference 成员初始化一次,并且仅一次,这是有道理的。

回答by e.James

Another option that has not been shown yet is to split your class into two, wrapping a lightweight interface class around your original class in order to achieve the effect you are looking for:

另一个尚未显示的选项是将您的类拆分为两个,在您的原始类周围包装一个轻量级接口类,以实现您正在寻找的效果:

class Test_Base {
    public Test_Base() {
        DoSomething();
    }
};

class Test : public Test_Base {
    public Test() : Test_Base() {
    }

    public Test(int count) : Test_Base() {
        DoSomethingWithCount(count);
    }
};

This could get messy if you have many constructors that must call their "next level up" counterpart, but for a handful of constructors, it should be workable.

如果您有许多构造函数必须调用它们的“下一级”对应物,这可能会变得混乱,但对于少数构造函数,它应该是可行的。

回答by izogfif

In Visual C++ you can also use this notation inside constructor: this->Classname::Classname(parameters of another constructor). See an example below:

在 Visual C++ 中,您还可以在构造函数中使用此表示法:this->Classname::Classname(parameters of another constructor)。请参阅下面的示例:

class Vertex
{
 private:
  int x, y;
 public:
  Vertex(int xCoo, int yCoo): x(xCoo), y(yCoo) {}
  Vertex()
  {
   this->Vertex::Vertex(-1, -1);
  }
};

I don't know whether it works somewhere else, I only tested it in Visual C++ 2003 and 2008. You may also call severalconstructors this way, I suppose, just like in Java and C#.

我不知道它是否在其他地方工作,我只在 Visual C++ 2003 和 2008 中测试过它。我想你也可以这样调用几个构造函数,就像在 Java 和 C# 中一样。

P.S.: Frankly, I was surprised that this was not mentioned earlier.

PS:坦率地说,我很惊讶之前没有提到这一点。