我一直试图严格地解决这个问题。鉴于三个类相互继承,序列如何工作? 例如:Classes Vehicle-> Car-> Mercedes
答案 0 :(得分:1)
复制构造函数的调用顺序是什么
顺序与其他构造函数相同。
如果有多个直接基地或成员,则按照声明的顺序构建。
在每个子对象构造之间,可以为下一个子对象执行初始化列表表达式。
例如:Classes Vehicle-> Car-> Mercedes
如果Car
是Mercedes
的基础,则在Car
的构造函数体执行之前构造Mercedes
base-sub-object。如果Vehicle
是Car
的基础,则在Vehicle
的构造函数体执行之前构造Car
base-sub-object。
答案 1 :(得分:1)
施工人员总是从下到上执行,所以首先是车辆,下一辆车,最后是梅赛德斯。 这种行为的原因是子类可能使用基类的变量,因此必须首先初始化它们。
Destructors以同样的方式回归:首先是梅赛德斯,然后是Car,最后是车辆,出于同样的原因。
答案 2 :(得分:1)
构造了显式和继承的第一个基础,然后是从左到右的顺序构造成员变量。所以,如果你有
class Base0;
class Subbase;
class Base1: Subbbase;
struct Der: Base0, Base1 {
Der();
Type member1;
Type member2;
};
然后初始化的顺序是Base0 - > Subbase - > Base1 - > member1 - > member2,然后进入ctor体(到那时所有碱基和成员都已经初始化)。
析构函数反向运行:body - > member2 - > member1 - > Base1 - > Subbase - > BASE0。
答案 3 :(得分:0)
足以创建MCVE ......
#include <chrono>
// 'compressed' chrono access --------------vvvvvvv
typedef std::chrono::high_resolution_clock HRClk_t; // std-chrono-hi-res-clk
typedef HRClk_t::time_point Time_t; // std-chrono-hi-res-clk-time-point
typedef std::chrono::milliseconds MS_t; // std-chrono-milliseconds
typedef std::chrono::microseconds US_t; // std-chrono-microseconds
typedef std::chrono::nanoseconds NS_t; // std-chrono-nanoseconds
using namespace std::chrono_literals; // support suffixes like 100ms, 2s, 30us
#include <iostream>
#include <iomanip>
class Vehicle_t
{
public:
Vehicle_t () { std::cout << "\n Vehicle_t" << std::flush; }
~Vehicle_t () = default;
};
class Car_t
: public Vehicle_t
{
public:
Car_t () { std::cout << "\n Car_t" << std::flush; }
~Car_t () = default;
};
class Mercedes_t
: public Car_t
{
public:
Mercedes_t () { std::cout << "\n Mercedes_t" << std::flush; }
~Mercedes_t () = default;
};
int main(int , char** )
{
int retVal = -1;
{
Time_t start_us = HRClk_t::now();
Mercedes_t m;
retVal = 0;
auto duration_us = std::chrono::duration_cast<US_t>(HRClk_t::now() - start_us);
std::cout << "\n\n duration " << duration_us.count() << " us" << std::endl;
}
return(retVal);
}
带输出
Vehicle_t
Car_t
Mercedes_t
初学者注意事项:
我确定您之前已经听过,&#34;执行开始于&#39; main&#39;&#34;。这段代码也是如此。
因此声明,&#34; Mercedes_t m;&#34;是第1(对于此类层次结构)。它显示了&#34; Mercedes_t&#34;的调用。首先调用ctor(派生最多)。
请记住,所有方法(和函数)都有一个入口和一个出口。
最派生的ctor调用&#34; Car_t&#34; ctor,它调用&#34; Vehicle_t&#34;构造函数。
输出显示&#34; Vehicle_t&#34; ctor cout声明首先完成。因此,你可以推断出这个ctor首先完成。
输出显示,下一个完成的ctor是&#34; Car_t&#34;,然后&#34; Mercedes_t&#34;
摘要
最后调用最基类,但最先完成。
首先调用派生类最多的类,但最后完成。
ctor Entry/Invocation sequence: Mercedes_t -> Car_t -> Vehicle_t ctor Exit/ctor completion seq : Vehicle_t -- Car_t -- Mercedes_t
update - 11/19/2017
我认为我的大部分答案都是关于实施细节。我突然想到这样的证据&#39;我上面提供的不足。 (并且与一个或多个替代答案相矛盾)。
更有说服力的证明&#39;是检查组件。以下是代码中的一些与我上面的MCVE不同的内容,但仍然具有可识别的名称。仅供参考 - 我的系统是Ubuntu 15.10,g ++报告(Ubuntu 5.2.1-23ubuntu1~15.10)5.2.1。
使用gdb,我在main(即b main)设置断点,发出run,然后使用命令
(gdb)反汇编/ m
找到了
154 { 155 Mercedes_t m; // invoke Mercedes_t ctor 0x00000000004019e2 <+40>: lea -0x30(%rbp),%rax 0x00000000004019e6 <+44>: mov %rax,%rdi 0x00000000004019e9 <+47>: callq 0x40214a <Mercedes_t::Mercedes_t()> 0x00000000004019ee <+52>: lea -0x30(%rbp),%rax
这确认了创建对象的第一个调用是 &LT; Mercedes_t :: Mercedes_t()&gt; ctor,即最先导出的ctor首先被召唤。
接下来,从Mercedes_t ctor的相同类型的反汇编中,您可以看到对&lt; Car_t :: Car_t()&gt;。
Dump of assembler code for function Mercedes_t::Mercedes_t():
91 Mercedes_t () : initLineNum (log(__LINE__)) // Mercedes_t ctor init
0x000000000040214a <+0>: push %rbp
0x000000000040214b <+1>: mov %rsp,%rbp
0x000000000040214e <+4>: sub $0x10,%rsp
0x0000000000402152 <+8>: mov %rdi,-0x8(%rbp)
=> 0x0000000000402156 <+12>: mov -0x8(%rbp),%rax
0x000000000040215a <+16>: mov %rax,%rdi
0x000000000040215d <+19>: callq 0x4020ec <Car_t::Car_t()>
0x0000000000402162 <+24>: mov $0x5b,%edi
0x0000000000402167 <+29>: callq 0x401616 <log(int)>
0x000000000040216c <+34>: mov %eax,%edx
0x000000000040216e <+36>: mov -0x8(%rbp),%rax
0x0000000000402172 <+40>: mov %edx,0x8(%rax)
对我来说足够了。我强烈建议你学习gdb。
但同样,我认为这些可能是实施细节。
更新 - 2017年11月20日 添加了识别复制ctor序列的代码。
我将复制ctor添加到每个班级(默认ctor之后,dtor之前):
Vehicle_t(const Vehicle_t& /*rhs*/){
std::cout << "\n Vehicle_t(rhs) " << std::flush; }//Vehicle_t copy ctor (3)
Car_t(const Car_t& rhs) : Vehicle_t(rhs) {
std::cout << "\n Car_t(rhs) " << std::flush; } // Car_t copy ctor (3)
Mercedes_t(const Mercedes_t& rhs) : Car_t(rhs) {
std::cout << "\n Mercedes_t(rhs) " << std::flush; } // Mercedes_t copy ctor (3)
在默认ctor之后,在&#34; retVal = 0之前为main添加了2行;&#34;
Mercedes_t m; // invoke default ctor
std::cout << "\n";
Mercedes_t m2(m); // invoke copy ctor
retVal = 0;
输出现在看起来像:
Vehicle_t
Car_t
Mercedes_t
Vehicle_t(rhs)
Car_t(rhs)
Mercedes_t(rhs)
这与默认ctors的序列相同。
我还使用了gdb和&#34;反汇编/ m&#34;命令并检查了总结。调用序列与默认ctor匹配。