C++中的构造函数可以调用另一个构造函数吗?

44
class A{
  A(int a = 5){
    DoSomething();
    A();
  }
  A(){...}
}

第一个构造函数可以调用第二个构造函数吗?


1
类似的问题在这里:https://https://dev59.com/5nVC5IYBdhLWcg3wZwJT - Jon Cage
6个回答

69

不是C++11之前的语法。

将常见功能提取到单独的函数中。我通常将此函数命名为construct()

"所谓"的第二次调用会编译通过,但在C++中具有不同的含义:它将构造一个新对象,即临时对象,然后在语句结束时立即删除。因此,不行。

然而,析构函数可以无问题地被调用。


5
+1- 并且你应该补充说明,在下一个C++版本(C++0x)中,将有可能在同一类的构造函数中调用其他构造函数。请参见http://www2.research.att.com/~bs/C++0xFAQ.html#delegating-ctor。 - Klaim
你能举一个construct()函数的例子吗?我知道这很简单,但我认为人们会觉得有用。 - MattCochrane
是的,真正的问题在于初始化引用时,如果你有一堆引用,你必须在每个构造函数重载中复制所有的初始化操作,并且无法将它们提取到一个公共的构造函数子程序中。而且它们只能在前置初始化器中初始化。 - peterk

19

C++0x 之前是不可能的。

但是,出于学术兴趣,我想到了一种非常可怕的方法*,使用放置 new 运算符(有人能指出这种方法的可移植性吗?)

#include <new>
#include <iostream>

class A
{
public:
    A(int i, int j)
        : i_(i), j_(j) { }

    A(int i)
    { new (this) A(i, 13); }

    int i_,j_;
};

int
main() {
    A a1(10,11), a2(10);
    std::cout
        << a1.i_ << ", "
        << a1.j_ << std::endl
        << a2.i_ << ", "
        << a2.j_ << std::endl;
    return 0;
}

*天哪,我不会在生产代码中写这个。


1
我认为它非常便携;placement-new在ISO C++标准中。然而,其他用途包括直接调用构造函数,这是C++语言不允许的。来自维基百科:http://en.wikipedia.org/wiki/Placement_syntax - emvee
4
如果A派生自类B,会发生什么?B的构造函数将被调用,接着是A,然后调用新的A'(另一个A构造函数),并覆盖B已经完成的一切,然后再次调用B,然后是A'。结论是:如果B执行了有意义的操作(例如分配资源),这将破坏代码(即导致资源泄漏)。 - paercebal
@paercebal 是的,如果 A 是一个抽象类,这也不起作用。 - Alex B

6
事实上,答案是“是”,但正如其他人所建议的那样,它并不能做到你想要的。当然,你可以使用基类的构造函数,无论是隐式还是显式地使用:
struct B {
    B() {}
    B( int x ) {}
};

struct A : public B {
    A() {}    // calls B() implicitly
    A( int a, int b ) : B( b ) {} // calls B(int) explicitly
};

3

不能直接实现。有几种方法可以解决这个问题。

从类构造函数的初始化列表中,您可以调用任何基类和所有成员变量的构造函数。

因此,通常可以将类重构并将其拆分为几个较小的类来解决问题。常见执行的代码可以放置在成员对象或基类中。然后,每个主类的构造函数只需决定使用哪个构造函数来初始化该成员。

class B {
  B() {  }
  B(int b) { DoSomething(); }
}
class A{
  A(int a = 5) : b(a) { } // call B's constructor which does something
  A() : b() {} // call B's constructor which does nothing

  B b;
};

3

这是一个老问题了;然而,

在IT技术领域仍然备受关注。
class A{
  A(int a = 5){
    DoSomething();
    A();
  }
  A(){...}
}

可能是

class A{
  A(int a = 5){
    *this = A();
    DoSomething();
  }
  A(){...}
}

1
我认为赋值 *this = A(); 会使用默认的复制构造函数(如果你没有定义的话),这可能不是你想要的结果? - austinmarton

3
正如Pavel Radzivilovsky在他的回答中指出的那样,从C++ 11开始就可以实现。这与从子类显式调用父类构造函数的语法相同。当一个类需要有多个构造函数(例如,一个默认构造函数和一个带属性初始化的构造函数),但某些操作必须在所有情况下执行时,这非常有用。这可以避免代码重复。
以下是一个例子:
class A
{
public:

    A()
    {
         foo();
    }

    A(Attribute attribute) : A()
    {
         this->attribute = attribute;
    }

    //------ some other code --------

private:

    Attribute attribute;
    void foo()
    {...}

    //------ some other code -------
};

在这个简单的示例中,我假设函数foo()需要在所有情况下都被调用才能正确初始化对象。使用这种语法,如果调用第二个构造函数(具有属性初始化),它将首先执行默认构造函数中的操作,然后再执行属性初始化构造函数中的指令。
也可以反过来:默认构造函数可以调用具有默认参数的另一个构造函数。
在 C++11 之前,必须复制所有构造函数的公共指令或定义实际对象初始化的方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接