多级继承中复制构造函数的调用顺序是什么?

pro_coder

我一直在努力解决这个问题。给定三个相互继承的类,序列如何工作?例如:Classes Vehicle->Car->Mercedes

2785528

很容易创建 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

初学者注意事项:

  1. 我相信你以前听说过,“执行开始于 'main'”。这段代码也可以。

  2. 因此声明,“Mercedes_t m;” 是第一个(对于这个类层次结构)。它显示了首先调用“Mercedes_t”构造函数(最派生的)的调用。

请记住,所有方法(和函数)都有入口和出口。

  1. 派生程度最高的 ctor 调用“Car_t” ctor,后者调用“Vehicle_t” ctor。

  2. 输出显示“Vehicle_t”ctor cout 语句首先完成。因此你可以推断这个ctor首先完成。

  3. 输出显示下一个要完成的 ctor 是“Car_t”,然后是“Mercedes_t”

概括

  • 最后调用最基类,但最先完成。

  • 派生程度最高的类首先被调用,但最后完成。

ctor Entry/Invocation sequence:   Mercedes_t -> Car_t -> Vehicle_t
ctor Exit/ctor completion seq :   Vehicle_t  -- Car_t -- Mercedes_t

更新 - 11/19/2017

我认为我的大部分答案都是关于实现细节的。我突然想到,我上面提供的这种“证据”是不够的。(并与一个或多个备选答案相矛盾)。

更有说服力的“证据”是检查装配。以下代码与上面的 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

这证实了创建对象的第一个调用是 < Mercedes_t::Mercedes_t() > ctor,即最先调用最派生的 ctor。

接下来,从Mercedes_t ctor的同类型反汇编中,可以看到对<Car_t::Car_t()>的调用。

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 之后,在 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)

在 main 中添加了 2 行,在默认 ctor 之后,在“retVal = 0;”之前

  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 和“disassemble /m”命令并检查了组件。调用序列与默认构造函数匹配。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

在C ++中,使用继承性调用析构函数的顺序是什么,销毁成员变量的顺序是什么?

来自分类Dev

在多级继承中查找构造函数

来自分类Dev

多级继承,无需调用超类构造函数

来自分类Dev

在继承中更改构造函数的顺序

来自分类Dev

为什么在此示例中调用了复制构造函数?

来自分类Dev

在C ++中调用构造函数的正确方法是什么?

来自分类Dev

继承的类中字段的顺序是什么?

来自分类Dev

多重继承中的构造函数调用序列

来自分类Dev

为什么不调用复制构造函数

来自分类Dev

为什么复制构造函数被调用?

来自分类Dev

为什么复制构造函数被调用?

来自分类Dev

为什么在我的代码中调用复制构造函数而不是移动构造函数?

来自分类Dev

为什么调用复制构造函数而不是移动构造函数?

来自分类Dev

为什么调用复制构造函数而不是移动构造函数?

来自分类Dev

什么时候调用复制构造函数或赋值构造函数?

来自分类Dev

C ++继承顺序以什么方式影响构造函数?

来自分类Dev

虚拟继承构造函数顺序

来自分类Dev

构造函数调用顺序

来自分类Dev

构造函数调用顺序

来自分类Dev

构造函数调用顺序

来自分类Dev

Java - 为什么实例块在构造函数之后调用或在构造函数中按顺序调用?

来自分类Dev

复制构造函数未继承

来自分类Dev

在复制构造函数定义中调用成员构造函数

来自分类Dev

为什么在对std :: vector :: emplace_back()的调用中调用了复制构造函数?

来自分类Dev

模板构造函数继承的标准符合语法是什么?

来自分类Dev

Java构造函数-继承层次结构中的执行顺序

来自分类Dev

我们可以在Java的多级继承中从第二个子类调用超类构造函数吗

来自分类Dev

为什么在函数返回时不调用复制构造函数?

来自分类Dev

在Python中中断嵌套函数/构造函数调用的正确方法是什么?

Related 相关文章

  1. 1

    在C ++中,使用继承性调用析构函数的顺序是什么,销毁成员变量的顺序是什么?

  2. 2

    在多级继承中查找构造函数

  3. 3

    多级继承,无需调用超类构造函数

  4. 4

    在继承中更改构造函数的顺序

  5. 5

    为什么在此示例中调用了复制构造函数?

  6. 6

    在C ++中调用构造函数的正确方法是什么?

  7. 7

    继承的类中字段的顺序是什么?

  8. 8

    多重继承中的构造函数调用序列

  9. 9

    为什么不调用复制构造函数

  10. 10

    为什么复制构造函数被调用?

  11. 11

    为什么复制构造函数被调用?

  12. 12

    为什么在我的代码中调用复制构造函数而不是移动构造函数?

  13. 13

    为什么调用复制构造函数而不是移动构造函数?

  14. 14

    为什么调用复制构造函数而不是移动构造函数?

  15. 15

    什么时候调用复制构造函数或赋值构造函数?

  16. 16

    C ++继承顺序以什么方式影响构造函数?

  17. 17

    虚拟继承构造函数顺序

  18. 18

    构造函数调用顺序

  19. 19

    构造函数调用顺序

  20. 20

    构造函数调用顺序

  21. 21

    Java - 为什么实例块在构造函数之后调用或在构造函数中按顺序调用?

  22. 22

    复制构造函数未继承

  23. 23

    在复制构造函数定义中调用成员构造函数

  24. 24

    为什么在对std :: vector :: emplace_back()的调用中调用了复制构造函数?

  25. 25

    模板构造函数继承的标准符合语法是什么?

  26. 26

    Java构造函数-继承层次结构中的执行顺序

  27. 27

    我们可以在Java的多级继承中从第二个子类调用超类构造函数吗

  28. 28

    为什么在函数返回时不调用复制构造函数?

  29. 29

    在Python中中断嵌套函数/构造函数调用的正确方法是什么?

热门标签

归档