2014-09-23 293 views
0

我知道这个问题有明确的答案:首先调用基类构造函数,然后调用派生类构造函数。基类构造函数在派生类构造函数之前真的调用

但我不完全理解“被叫”这个词。这是否意味着构造函数的使用开始,还是构造函数的使用完成?换句话说,对于下面的代码两种可能的顺序:

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

  2. DerivedClass构造函数启动 - > BaseClass构造函数启动 - > BaseClass构造函数完成 - > DerivedClass构造函数完成。

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

看来情况2是正确的:“调用”应该意味着构造函数的完成。后续问题是如何解析器?我知道标准答案是“派生类的析构函数被称为第一个”。因此,这是正确的顺序为:

  • DerivedClass析构函数开始
  • DerivedClass析构函数完成
  • BaseClass的析构函数开始
  • BaseClass的析构函数完成

感谢

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

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

int main() { 
    DerivedClass dc; 
} 
+2

为什么不运行该程序并找出答案? – 2014-09-23 14:13:23

+0

试试看,一个重要的座右铭;)。 – 2014-09-23 14:13:54

+2

如果2是正确的,那么在派生类构造函数中的基准类构造函数是否会被“注入”?编译器如何做出该决定? – 2014-09-23 14:14:20

回答

0

的CORRE CT的答案是选择1,但可以通过实际运行你已经输入了

+0

您无法单独通过观察来验证保证。 – 2014-09-23 14:50:43

5

[class.base.init]/10的编码很容易地验证,重点煤矿:

在非委托构造,按照以下顺序在 初始化前进:

  • 首先,并只对最 派生类的构造函数,虚基类被初始化[...]

  • 然后,如它们出现在碱说明符列表 (无论MEM-初始化的量级)直接基类在 声明的顺序初始化

  • 然后,非静态 数据成员在他们在 类定义被宣布(再次不管 MEM-初始化的顺序)的顺序初始化。

  • 最后,构造体的化合物语句执行

即,派生类的构造函数被‘称为’第一,但其化合物语句(其功能体)之前,基类构造函数必须完成。我们可以看到这个命令


的一种方法是使用功能试块在派生类的构造函数:

#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

功能试块可以捕获基础和成员初始化期间发生的异常。该异常是隐式传播的:由于基本/成员不能被构造/初始化,(派生)对象不能被构造/初始化。


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

执行析构函数的主体和破坏人体内分配的任何自动对象之后,对于X类析构函数调用析构函数X的直接非变量非静态数据成员,破坏函数 为X的直接基类,如果X是最派生类的类型,其析构函数调用的析构函数10的虚拟基类。

调用所有析构函数,就好像它们被引用了合格的 名称,即忽略更多派生类中的任何可能的虚拟覆盖析构函数。按照完成构造函数的相反顺序销毁基地和成员。

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

+0

感谢您的意见@dyp。你的意思是对于析构函数来说,构造函数的顺序应该是相似的吗? DerivedClass析构函数启动 - > BaseClass析构函数启动 - > BaseClass析构函数完成 - > DerivedClass析构函数完成。 – cgao 2014-09-23 15:36:05

+0

不,正如引用所述:“在执行析构函数的主体[...]之后,类'X'的析构函数调用了'X'的直接基类的析构函数[...] ]“。也就是,顺序是:'〜Derived()'starts - >'〜Derived()'的主体完成 - >'〜Base()'starts - >'〜Base()'的主体完成。对于* *体的执行,构造函数和析构函数之间的顺序是相反的。 – dyp 2014-09-23 15:45:18

相关问题