为什么一个ctor不能调用另一个ctor来初始化该对象

时间:2010-03-16 18:01:14

标签: c++

class Foo {

 public:
  Foo() { Foo(1)}
  Foo(int x, int y = 0):i(x) {}
 private:
  int i;
}

有人可以给我一些理由我可以这样做吗?如果不是为什么?

5 个答案:

答案 0 :(得分:10)

因为语言规范不允许它。就像语言一样。如果您习惯使用Java或其他允许它的语言,那会非常烦人。但是,你会在一段时间后习惯它。所有语言都有它们的怪癖,这只是C ++的一个。我确信这些规格的作者有他们的理由。

我发现最好的方法是创建一个通用的初始化函数,让两个构造函数都调用它。

这样的事情:

class Foo {
public:
    Foo() {initialize(1);}
    Foo(int nX) { initialize(nx); }

private:
    void initialize(int nx) { x=nx; }
    int x;
};

答案 1 :(得分:4)

这是语言设计的选择。

构造函数是一次(每个对象)操作,它在未初始化的内存中创建一个新对象。只有一个构造函数可以为对象调用,一旦它完成了对象的生命周期开始,就不能在该对象上调用或恢复其他构造函数。

在其生命的另一端,析构函数只能(有效地)被调用每个对象一次,并且一旦进入析构函数,对象的生命周期就结束了。

这样做的一个主要原因是当一个对象析构函数运行时它是明确的,以及它可以指望该对象处于什么状态。

如果一个类构造函数成功完成,那么它的析构函数将被调用,否则该对象的生命周期从未开始,并且不会调用析构函数。当对象在其构造函数中获取需要在其析构函数中释放的资源时,此保证可能很重要。如果资源获取失败,那么通常会使构造函数失败;如果析构函数仍然运行,它可能会尝试释放从未成功获取的资源。

如果允许构造函数相互调用,则可能不清楚调用或被调用的构造函数是否负责该资源。例如,如果调用的构造函数在被调用的构造函数返回后失败,那么析构函数是否应该运行?被调用的构造函数可能已经获得了需要释放的东西,或者这可能导致调用构造函数失败并且不应该调用析构函数,因为资源句柄永远不会有效。

为简化破坏规则,如果每个对象由单个构造函数创建,并且 - 如果成功创建 - 由单个析构函数销毁,则更简单。

请注意,在C ++ 11中,构造函数可以委托给不同的构造函数,但是有一些限制并没有真正放松每个对象的一个​​构造的主体。 (主要构造函数可以转发到目标构造函数,但如果它的话,它不能在其初始化列表中命名任何其他内容(基类或成员)。一旦目标构造函数返回主体,它们将由目标构造函数初始化。 prinicipal构造函数将完成(进一步初始化)。虽然它允许你在构造函数之间共享构造函数代码,但是不可能重新构造任何基础或成员。)

答案 2 :(得分:2)

你不能这样做。见第10.3节:http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.3。您可以尝试这样做,但这样做会构造一个新的临时对象(而不是这个)并在控件移动时被销毁。

然而,您可以创建一个初始化变量的私有函数,一个默认构造函数或参数化构造函数都可以调用的函数。

答案 3 :(得分:2)

我曾经看到过一个非常可怕的黑客攻击另一个ctor。它在this指针上使用放置新操作。 ERK

像这样:

Class::Class(int x) : x_(x) {}
Class::Class() {
    new (this) Class(0);
}
Class::Class(const Class &other) : x_(other.x_) {}
Class& operator=(const Class &other) {
    new (this) Class(other);
    return *this;
}

请注意,我不推荐这个,我不知道它可能会对C ++结构(如虚拟基类等)造成什么可怕的影响。但我希望有一些。

答案 4 :(得分:0)

虽然根据标准,供应商可以自己的方式自由地实现数据绑定,但如果我们考虑最流行的实现:这个指针,我们可以看到无法实现这一点的原因。

假设您有一个班级:

class A
{
    public:
    A(){}
    A(int a){}
} ;

使用this指针实现,这个类看起来像:

class A
{
    public:
    A(A *this){}
    A(A *this,int a){}
} ;

通常你会创建这样的对象:

A ob ;

现在,当编译器看到这个时,它会为此分配内存,并将此分配的内存块的地址传递给A的构造函数,然后构造该对象。它会尝试每次为每个被称为。

的构造函数执行相同的操作

现在,当您尝试在另一个构造函数中调用构造函数时,编译器应该传递当前对象,而不是分配新内存。因此不一致!

然后我看到的另一个原因是,即使您可能想在另一个内部调用构造函数,您仍然希望构造函数为类中的所有对象调用默认构造函数。现在,如果一个构造函数调用另一个构造函数,则默认构造应该发生在第一个构造函数而不是后续构造函数。实现此行为意味着需要处理多个排列。如果没有,则性能降低,因为每个构造函数将默认构造所有包含的对象。

这是我可以想到的这种行为的可能原因,并且没有任何标准可以支持。