在 C++ 对象中,当您从另一个构造函数或成员函数调用构造函数时(在已构造对象之后),您正在调用的构造函数的初始化列表是否仍会执行?
4 回答
在 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++ 要求基类构造函数始终在派生类构造函数之前调用——无论对基类构造函数的调用是否显式出现在派生类的初始化列表中——也不管它出现在初始化列表中的什么位置。
不要从另一个方法或另一个构造函数显式调用构造函数。
如果您确实需要,请使用两阶段初始化,其中您Init()
在构造对象后调用类型方法。
您不能显式调用构造函数,只能通过 new 或堆栈上的对象构造来调用。有办法破解它(例如放置新),但不要这样做,只需使用两阶段构造和初始化。