从另一个成员函数/构造函数调用C++构造函数是否执行初始值设定项列表

Does calling a C++ constructor from another member function/constructor execute the initializer list?

本文关键字:执行 列表 是否 构造函数 函数 成员 另一个 C++ 函数调用      更新时间:2023-10-16

在C++对象中,当您从另一个构造函数或成员函数调用构造函数时(在对象已构造之后(,您正在调用的构造函数的初始值设定项列表是否仍会执行?

在 C++11 中,你可以让一个构造函数将工作委托给同一类中的另一个构造函数,例如 1

#include <iostream>
struct SomeType  {
    int number;
    SomeType(int new_number) : number(new_number) {}
    SomeType() : SomeType(42) {}
};
int main() {
  SomeType a;
  std::cout << a.number << std::endl;
}

在这种情况下,禁止在此委派之后有一个初始化器列表,例如将前面的示例更改为:

SomeType() : SomeType(42), number(0) {}

是一个错误。


如果问题是"给定继承关系,发起者列表仍然被调用吗?"答案是肯定的,例如

#include <iostream>
struct SomeBase {
  SomeBase(int) {}
};
struct SomeType : SomeBase {
    int number;
    SomeType(int new_number=0) : SomeBase(new_number), number(new_number) {}
};
int main() {
  SomeType a;
  std::cout << a.number << std::endl;
}

这很好,并且完全按照您希望的方式工作。


直接从另一个构造函数中调用构造函数是不合法的,并且在 C++11 之前的C++中也不允许构造函数委托,因此如下所示:

#include <iostream>
struct SomeType {
    int number;
    SomeType(int new_number) : number(new_number) {}
    SomeType() {
      SomeType::SomeType(0); // Error!
    }
};
int main() {
  SomeType a;
  std::cout << a.number << std::endl;
}

是一个错误,不能直接表达。

然而,以下(我猜这是您在编写问题时想到的(示例不是错误,但并没有起到您可能希望的作用:

#include <iostream>
struct SomeType {
    int number;
    SomeType(int new_number) : number(new_number) {}
    SomeType() {
      SomeType(0); 
      number = 42;
    }
};
int main() {
  SomeType a;
  std::cout << a.number << std::endl;
}

在这里,没有参数的构造函数构造 SomeType 的匿名临时实例。它与最初调用构造函数的实例完全不同。这是完全合法的,但可能不是你想做的。如果你这样做,如果你不小心,你可能会创建无限递归,我认为如果你最终做了这样的事情,这可能是设计问题的一个很好的指标!

1 源自维基百科C++11文章

我假设你指的是从派生类的初始化列表中调用基类构造函数。 假设是这种情况,则首先执行 BASE 类构造函数(包括其初始值设定项列表(,然后调用派生类的初始值设定项列表。

如果您想知道 - 基类构造函数总是在为派生类执行初始值设定项列表之前调用,即使对基类构造函数的调用显式出现在派生类的初始化器列表的中间或末尾(以及如果它出现在开头(。 原因是初始值设定项列表中的项按照它们在类头文件的类 DECLARATION 中出现的顺序执行,而不是按照它们在构造函数定义的初始值设定项列表中出现的顺序执行。 并且,类构造函数永远不会在派生类声明中声明。 C++要求基类构造函数始终在派生类构造函数之前调用 - 无论对基类构造函数的调用是否显式出现在派生类的初始值设定项列表中 - 并且无论它出现在初始值设定项列表中的哪个位置。

不要从另一个方法或其他构造函数显式调用构造函数。

如果确实需要 in,请改用两阶段初始化,即在构造对象后调用 Init() 类型方法。

不能显式调用构造函数,只能通过 new 或堆栈上的对象构造来调用构造函数。有一些方法可以破解它(例如放置新(,但不要这样做,只需使用两个阶段的构造和初始化。