当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《我可以在C++中从另一个构造函数(构造函数链接)调用构造函数吗?》经验,为你挑选了8个好方法。

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

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

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

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

有没有办法在C++中执行此操作?

我尝试调用类名并使用'this'关键字,但都失败了.



1> JohnIdol..:

C++ 11:是的!

C++ 11及更高版本具有相同的功能(称为委托构造函数).

语法与C#略有不同:

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

C++ 03:没有

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

    您可以通过默认参数组合两个(或更多)构造函数:

    class Foo {
    public:
      Foo(char x, int y=0);  // combines two constructors (char) and (char, int)
      // ...
    };
    

    使用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)
    {
      // ...
    }
    

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


实际上非常默认的参数使得_very clean_方式可以做我们通常在C#中调用this()的方法
@bobobobo使用默认参数将它们编译到调用者中,因此不是_very_ clean.重载是更多的代码,正确,但实现封装了默认值.
请注意,如果要构造的类没有继承或常量字段,则不使用C++ 11的建议解决方案才有效.我没有找到初始化初始化列表之外的父类和常量字段的方法.
使用init()的一个缺点是,如果不在构造函数()中初始化它,则不能声明指针或ref为const(如在ref /指针中是const而不是它指向的东西).
@gen(除了缺少的第二个冒号),它将创建一个临时Foo,然后立即将其丢弃。

2> Cyrille Ka..:

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

这在C++ 11(又名C++ 0x)中有所改变,它增加了对以下语法的支持:(
来自维基百科的示例)

class SomeType
{
  int number;

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


@TomášZato另一个区别是,使用默认参数,您只需要一个构造函数,您必须使用public,protected或private,而使用2个构造函数,一个调用另一个,您可以限制对其中一个的访问,而不必限制访问到另一个.
但是这与标准默认参数语法有何不同?
它也与默认值不同,因为您可以在不重新编译使用库的代码的情况下进行更改.使用默认值,这些值将"烘焙"到调用中.

3> ohlemacher..:

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

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

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


这不是"调用构造函数".您可以直接"调用构造函数"的_only_位置在C++ 11的_ctor-initializer_中.你在这个例子中所做的是构建一个对象,这是一个不同的鱼.不要因为_looks_就像对构造函数的函数调用那样被误导,因为它是_not_ one!实际上没有办法对构造函数进行函数调用,这就是为什么不可能构造一个类的实例,该类的唯一构造函数是函数模板的实例化,其模板参数不能推导出来.
好点子; 大多数人只是说"不,你不能".我可以 :).我做了这个切换回来,并使用原来的ctor决定调用哪个其他.在调试中,可以在第二个中看到对象,所有内容都被初始化但返回时返回默认值.当你想到它时会有很多意义.

4> kchoose2..:

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

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

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

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



5> Ben L..:

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

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

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

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

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



6> lyngvi..:

如果你想成为邪恶的,你可以使用就地"新"运算符:

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

似乎为我工作.

编辑

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

一个更一般的例子:

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

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

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


它似乎不是建议做的事情,因为你可以在10.3结束时阅读http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.3
这真是邪恶。假设您正在该构造函数中分配内存,并在析构函数中对其进行分配。没有内存将被释放。
但是,如果您在new(this)Foo();之前显式调用析构函数,则仍然可以从灾难中摆脱出来:`this->〜Foo();`。

7> unwind..:

不,在C++中,您无法从构造函数中调用构造函数.沃伦指出,你能做的是:

使用不同的签名重载构造函数

在参数上使用默认值,以使"更简单"的版本可用

请注意,在第一种情况下,您无法通过从另一个构造函数调用来减少代码重复.您当然可以使用一个单独的private/protected方法来执行所有初始化,并让构造函数主要处理参数处理.



8> 小智..:

简而言之,您不能在C ++ 11之前。

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

委托构造函数

如果类本身的名称在成员初始值设定项列表中显示为class-or-identifier,则该列表必须仅由该一个成员初始值设定项组成;这样的构造函数称为委托构造函数,并且由初始化程序列表的唯一成员选择的构造函数是目标构造函数

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

委托构造函数不能是递归的。

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

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

推荐阅读
U友50081205_653
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有