gpt4 book ai didi

c++ - 基类构造函数真的在派生类构造函数之前被调用

转载 作者:太空宇宙 更新时间:2023-11-04 16:13:05 25 4
gpt4 key购买 nike

我知道这个问题有明确的答案:先调用基类构造函数,再调用派生类构造函数。

但是“叫”这个词我不是很懂。是构造函数开始使用,还是构造函数使用结束?换句话说,下面的代码有两种可能的顺序:

  1. BaseClass 构造函数开始 -> BaseClass 构造函数完成 -> DerivedClass 构造函数开始 -> DerivedClass 构造函数完成。

  2. DerivedClass 构造函数开始 -> BaseClass 构造函数开始 -> BaseClass 构造函数完成 -> DerivedClass 构造函数完成。

哪一个应该是正确的顺序?如果 1 是正确的,编译器如何知道在我们初始化 DerivedClass 实例之前调用 BaseClass 构造函数?

似乎情况 2 是正确的:“被调用”应该意味着构造函数的完成。后续问题是析构函数如何?我知道标准答案是“首先调用派生类的析构函数”。那么哪个是正确的顺序:

  • DerivedClass析构函数启动
  • DerivedClass 析构函数完成
  • BaseClass析构函数开始
  • 基类析构函数完成

谢谢

class BaseClass {
public:
BaseClass() {
cout << "BaseClass constructor." << endl;
}
};

class DerivedClass : public BaseClass {
public:
DerivedClass() : BaseClass() {
cout << "DerivedClass constructor." << endl;
}
};

int main() {
DerivedClass dc;
}

最佳答案

[class.base.init]/10,强调我的:

In a non-delegating constructor, initialization proceeds in the following order:

  • First, and only for the constructor of the most derived class, virtual base classes are initialized [...]

  • Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).

  • Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).

  • Finally, the compound-statement of the constructor body is executed.

也就是说,派生类的构造函数首先被“调用”,但在它的复合语句(它的函数体)之前,基类构造函数必须完成。


我们可以看到这个顺序的一种方法是在派生类的 ctor 中使用 function-try-block:

#include <iostream>

struct Base {
Base() { throw "Base throwing\n"; }
};

struct Derived : Base{
Derived()
try : Base()
{}
catch(char const* p) {
std::cout << p;
}
};

int main() {
try { Derived d; }catch(...){}
}

Live example

function-try-block 可以捕获在基类和成员初始化期间发生的异常。隐式传播异常:由于无法构造/初始化基/成员,因此无法构造/初始化(派生)对象。


对于析构函数,[class.dtor]/8

After executing the body of the destructor and destroying any automatic objects allocated within the body, a destructor for class X calls the destructors for X’s direct non-variant non-static data members, the destructors for X’s direct base classes and, if X is the type of the most derived class, its destructor calls the destructors for X’s virtual base classes.

All destructors are called as if they were referenced with a qualified name, that is, ignoring any possible virtual overriding destructors in more derived classes. Bases and members are destroyed in the reverse order of the completion of their constructor.

如果析构函数是虚拟的,编译器(有时)无法知道必须在析构站点/翻译单元调用哪些析构函数(最派生类型及其基类)。因此,析构函数本身必须调用基类和成员的析构(至少对于通过动态调度调用的虚拟析构函数)。

关于c++ - 基类构造函数真的在派生类构造函数之前被调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25997329/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com