【问题标题】:Constructor chaining in C++C ++中的构造函数链接
【发布时间】:2011-09-08 13:54:32
【问题描述】:

我对构造函数链接的理解是,当一个类中有多个构造函数(重载构造函数)时,如果其中一个试图调用另一个构造函数,那么 这个过程称为 CONSTRUCTOR CHAINING ,在 C++ 中不受支持。 最近在看网上资料的时候偶然发现了这一段……是这样的……

您可能会发现自己需要编写一个成员函数来将一个类重新初始化为默认值。因为您可能已经有一个执行此操作的构造函数,所以您可能很想尝试从您的成员函数调用构造函数。如前所述,链接构造函数调用在 C++ 中是非法的。您可以从函数中的构造函数复制代码,这会起作用,但会导致重复代码。在这种情况下,最好的解决方案是将代码从构造函数移到新函数中,并让构造函数调用您的函数来完成初始化数据的工作。

调用构造函数的成员函数是否也属于构造函数链? 请用 C++ 阐明这个主题。

【问题讨论】:

  • 我会说不是,文章说构造函数链接是非法的,这是不合理的,紧接着说一些任意成员函数(不一定是构造函数)可能认为它想要调用构造函数来重置值。但谁知道呢,你没有引用这篇文章,也没有引用它描述构造函数链接的地方,所以它可能是在其他地方已经描述的某种不寻常的意义上使用它。
  • 这并不违法。从成员调用构造函数具有创建应用构造的临时对象的效果,而不是从中进行调用的“this”对象。
  • @Amardeep:同意,更准确地说,构造函数链接在 C++03 中是“不可能的”,而不是“非法的”。根本没有语法来描述这样做。正如您所说,按照正常定义,调用构造函数与构造函数链接完全不同。
  • @Steve .. 和其他感兴趣的人.. 这是link :)
  • C++构造函数调用另一个构造函数是c++ 11中的一个特性,叫做Delegating Constructors,见链接open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1986.pdf

标签: c++ constructor specifications constructor-chaining


【解决方案1】:

C++11 允许构造函数链接(部分)。此功能称为“delegating constructors”。因此,在 C++11 中,您可以执行以下操作

class Foo
{
public:
    Foo(int a) : Foo() { _a = a; }
    Foo(char* b) : Foo() { _b = b; }
    Foo() { _c = 1.5; }
private:
    int _a = 0;
    char* _b = nullptr;
    double _c;
};

但是,有一个严格的限制,即不允许调用另一个构造函数的构造函数来初始化任何其他成员。因此,您不能使用委托构造函数执行以下操作:

class Foo
{
public:
    Foo(int a) : Foo(), _a(a) { }
    Foo(char* b) : Foo(), _b(b) { }
    Foo() { _c = 1.5; }
private:
    int _a = 0;
    char* _b = nullptr;
    double _c;
};

MSVC++2013 给出后一个代码示例的编译错误“C3511:对委托构造函数的调用应是唯一的成员初始化程序”。

【讨论】:

  • 我想这是有道理的。调用默认构造函数应该初始化所有字段,因此再次初始化它们可能会非常糟糕。
  • 如果你觉得你需要这样做,这表明有一个小的父类试图离开Foo。在这种情况下,FooParent 将拥有成员 cFooChild 将从它继承并添加 ab
【解决方案2】:

该段基本上是这样说的:

class X
{
   void Init(params) {/*common initing code here*/ }
   X(params1) { Init(someParams); /*custom code*/ } 
   X(params2) { Init(someOtherParams); /*custom code*/ } 
};

您也不能从成员函数中调用构造函数。在你看来,你已经做到了,但那是一种错觉:

class X
{
public:
    X(int i):i(i){}
    void f()
    {
       X(3); //this just creates a temprorary - doesn't call the ctor on this instance
    }
    int i;
};

int main()
{
    using std::cout;
    X x(4);
    cout << x.i << "\n"; //prints 4
    x.f();
    cout << x.i << "\n"; //prints 4 again
}

【讨论】:

  • @Armen .. 你的意思是它第一次打印 4 时,它实际上是在调用构造函数,第二次打印 4 时,虽然我觉得我已经通过调用实现了结果构造函数(来自函数 void f() ),到底发生了什么不是那个.. !!!是吗 ??但是我不明白您在上面代码中的第一条评论 // 这只是创建了一个临时的 - 不会在这个实例上调用 ctor。你能解释清楚一点吗?
【解决方案3】:

这不是文本所说的。它建议您的构造函数调用一个正常且合法的成员函数。这是为了避免再次显式调用 ctor 并避免在 ctor 和 reset 函数之间重复代码。

Foo::Foo() {
  Init();
}

void Foo::Reset() {
  Init();
}

void Foo::Init() {
  // ... do stuff ...
}

【讨论】:

  • 确实,文本不建议函数调用构造函数,但是文本说“您可能很想尝试从成员函数调用构造函数。如上所述,链接构造函数调用是在 C++ 中是非法的”。这表明作者通过一些混淆的想法,认为“链式构造函数调用”与“从你的成员函数调用构造函数”有关,无论文章是否推荐这样做。当然,可能只是狡猾的编辑。
  • “因为您可能已经有一个构造函数来执行此操作,所以您可能会尝试从您的成员函数中调用构造函数。”我认为这意味着应该避免调用构造函数的成员函数.. !!???
  • @Appy:不一定。例如,在一个名为Foo 的类中,*this = Foo(); 可能是重置对象的一种完全合理的方法,但不一定是最有效的方法。然后函数调用构造函数,它只是不调用它来构造this
  • @ Steve ...感谢您的帮助.. :) 我想这只是一些狡猾的编辑..
【解决方案4】:

我不确定它(从成员函数调用构造函数)是否有效,但这是一种不好的做法。将初始化代码移动到新函数是逻辑方式。

基本上说,除非你在构造......否则不要调用构造函数......

【讨论】:

  • 我同意 Johnsyweb。从另一个构造函数调用只会在其中创建一个临时局部变量,并在构造函数退出后将其删除。 this 对象不受任何影响。做到这一点的唯一方法是放置新位置,C++ 常见问题解答重复了很多次,这是一件可怕的事情。
【解决方案5】:

当我们从成员函数中调用构造函数时,它会临时创建一个其类型的对象。 如果我们在派生类函数中调用,那么一旦函数超出范围,所有父构造函数也会被执行并使用析构函数销毁。

在成员函数中调用构造函数不是一个好习惯,因为它会创建每个派生类的对象。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-23
    • 1970-01-01
    • 2013-02-07
    • 1970-01-01
    • 2010-12-21
    • 1970-01-01
    相关资源
    最近更新 更多