先初始化序列中的函数调用,如果基类构造函数为非引用传递,则引起参数的拷贝构造

再: 先类内的成员构造函数(拷贝/默认),再类的构造函数;先基类,再派生类;

本文主要说明对象创建时构造函数的执行顺序,对象成员的初始化顺序;对象销毁时析构函数的执行顺序,对象成员的销毁顺序。

“对象的构造从类层次的最根处开始,在每一层中,首先调用基类的构造函数,然后调用成员对象的构造函数。析构则严格按照与构造相反的次序执行,该次序是唯一的,否则编译器将无法自动执行析构过程。

一个有趣的现象是,成员对象初始化的次序完全不受它们在初始化表中次序的影响, 只由成员对象在类中声明的次序决定。这是因为类的声明是唯一的,而类的构造函数可以有多个,因此会有多个不同次序的初始化表。如果成员对象按照初始化表的次序进行构造,这将导致析构函数无法得到唯一的逆序。”(引用自References[1])

从这里看,每种语言特性的存在必有其原因,学习这些特性就是理解这些特性存在的原因。

下面的一段代码是对上面这段话的说明,其中有4个类Foo, Bar, Base, Derived,它们的构造函数、拷贝构造函数、析构函数都有信息输出。

  1. #Filename: ConstructSequence.cc
  2. #include <iostream>
  3. using namespace std;
  4. class Foo
  5. {
  6. public:
  7. Foo() { cout << "Foo constructor" << endl; }
  8. Foo(const Foo &foo) { cout << "Foo copy constructor" << endl; }
  9. ~Foo() { cout << "Foo deconstructor" << endl; }
  10. };
  11. class Bar
  12. {
  13. public:
  14. Bar() { cout << "Bar constructor" << endl; }
  15. Bar(const Bar &bar) { cout << "Bar copy constructor" << endl; }
  16. ~Bar() { cout << "Bar deconstructor" << endl; }
  17. };
  18. class Base
  19. {
  20. public:
  21. Base() { cout << "Base constructor" << endl; }
  22. ~Base() { cout << "Base deconstructor" << endl; }
  23. };
  24. class Derived : public Base
  25. {
  26. public:
  27. Derived() { cout << "Derived constructor without arguments" << endl; }
  28. Derived(const Foo &foo, const Bar &bar);
  29. Derived(const Bar &bar, const Foo &foo);
  30. ~Derived() { cout << "Derived deconstructor" << endl; }
  31. private:
  32. Foo m_foo;
  33. Bar m_bar;
  34. };
  35. Derived::Derived(const Foo &foo, const Bar &bar) :
  36. m_foo(foo),
  37. m_bar(bar)
  38. {
  39. cout << "Derived constructor with argument[Foo foo, Bar bar] passed by references" << endl;
  40. }
  41. Derived::Derived(const Bar &bar, const Foo &foo) :
  42. m_bar(bar),
  43. m_foo(foo)
  44. {
  45. cout << "Derived constructor with argument[Bar bar, Foo foo] passed by references" << endl;
  46. }
  47. int main (int argc, char** argv)
  48. {
  49. Foo foo;
  50. Bar bar;
  51. cout << "test case 1:" << endl;
  52. Derived deri_1;  //  (1)
  53. cout << "test case 2:" << endl;
  54. Derived deri_2(foo, bar);   //  (2)
  55. cout << "test case 3:" << endl;
  56. Derived deri_3(bar, foo);   //  (3)
  57. cout << "test case end" << endl;
  58. return 0;
  59. }

执行结果是:

打印出的信息可分为几部分:

(1) 创建对象foo和bar ,执行Foo,Bar的构造函数

(2) Test Case 1:创建对象deri_1,首先执行基类Base的构造函数,其次执行成员m_foo,m_bar的构造函数来构造成员,最后调用自身的构造函数(无参数)。

(3) Test Case 2:创建对象deri_2,调用顺序与case 1顺序相同。

(4) Test Case 3:创建对象 deri_3,调用顺序与case 1顺序相同。注意到deri_2,deri_3的创建执行的是不同的Derived构造函数,虽然构造函数参数的顺序不同,但是构造成员的顺序是相同的。

(5) 销毁对象deri_3,deri_2,deri_1,析构函数执行顺序相同,与构造对象的顺序相反。C++标准规定以对象声明相反的顺序销毁这些对象。

(6) 销毁对象bar,foo。

编译运行环境:

  1. $ uname -a
  2. Linux localhost.localdomain 2.6.18-308.el5 #1 SMP Fri Jan 27 17:17:51 EST 2012 x86_64 x86_64 x86_64 GNU/Linux
  3. $ g++ --version
  4. g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-52)

References:

[1]高质量C++编程指南: http://oss.org.cn/man/develop/c&c++/c/c.htm

[2] http://stackoverflow.com/q/15948381/1145750

转载本文请注明作者和出处[Gary的影响力]http://garyelephant.me,请勿用于任何商业用途!

C++-理解构造函数、析构函数执行顺序的更多相关文章

  1. C# 父子类_实例_静态成员变量_构造函数的执行顺序

    今天去面试的时候被一道题问得一点脾气都没有,今天特地来研究下. 子类成员变量,子类静态成员变量,子类构造函数,父类成员变量,父类静态成员变量,父类构造函数的执行顺序. 现在贴上从另外一个.net程序员 ...

  2. Java的初始化块、静态初始化块、构造函数的执行顺序及用途探究

    Java与C++有一个不同之处在于,Java不但有构造函数,还有一个”初始化块“(Initialization Block)的概念.下面探究一下它的执行顺序与可能的用途. 执行顺序 首先定义A, B, ...

  3. 0708关于理解mysql SQL执行顺序

    转自 http://www.jellythink.com/archives/924,博客比价清晰 我理解上文的是SQL执行顺序 总体方案.当你加入索引了以后,其实他的执行计划是有细微的变化,比方说刚开 ...

  4. Java组合与继承生成的类中构造函数的执行顺序

    [程序实例] import java.util.*; class Meal{ Meal() { System.out.println("Meal Constructor"); } ...

  5. C++构造函数和析构函数执行顺序

    四种情况:1. 创建一个类指针时,调用其构造函数:删除当前指针时,自动调用其析构函数.2. 创建子类对象指针时,首先调用其父类的构造函数,然后调用子类的构造函数:删除当前指针时先调用子类的析构函数,然 ...

  6. c++派生类中构造函数和析构函数执行顺序、判断对象类型、抽象类、虚函数

    一. 代码: 1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #include&l ...

  7. C#基础知识之父子类,实例、静态成员变量,构造函数的执行顺序(经典示例)

    父子类.示例.静态成员变量.构造函数的概念的基础理解完全可以利用下面的示例诠释,非常经典,直接上代码: public class ShowInfo { public ShowInfo(string i ...

  8. Java基础 静态块、非静态块、构造函数的执行顺序

    Java中经常有一些静态块,这是用来在生成类之前进行的初始化,无论java还C++语言中的static,都是最先初始化好的.结构如下: static { 静态语句代码块 } { 非静态语句代码块 }  ...

  9. java子类和父类中静态块、非静态块、构造函数的执行顺序

    public class qqqq extends Parent{ public static void main(String[] args) { new Child(); } } class Pa ...

随机推荐

  1. maven编译项目时提示:cached in the local repository

    今天使用命令mvn compile编译maven项目时提示错误信息,部分错误信息如下: ...... was cached in the local repository, resolution wi ...

  2. JAVA调用C语言写的SO文件

    JAVA调用C语言写的SO文件 因为工作需要写一份SO文件,作为手机硬件IC读卡和APK交互的桥梁,也就是中间件,看了网上有说到JNI接口技术实现,这里转载了一个实例 // 用JNI实现 // 实例: ...

  3. 解决SQL命令行回退的问题

    场景 在linux或者aix上安装后Oracle后,在SQL命令行下无法通过键盘的退格键回退,如下 解决方法 安装软件 # rpm -ivh rlwrap-0.41-1.el6.x86_64.rpm ...

  4. shell脚本中获取本机ip地址的方法

    ipaddr='172.0.0.1' ipaddr=$(ip addr | awk '/^[0-9]+: / {}; /inet.*global/ {print gensub(/(.*)\/(.*)/ ...

  5. Source Insight 中使用 AStyle 代码格式工具

    Source Insight 中使用 AStyle 代码格式工具 彭会锋 2015-05-19 23:26:32     Source Insight是较好的代码阅读和编辑工具,不过source in ...

  6. 《javascript高级程序设计》第21章 Ajax和Comet

    21.1 XMLHttpRequest 对象  The XMLHttpRequest Object 21.1.1 XHR 的用法 XHR Usage 21.1.2 HTTP 头部信息 XHR Head ...

  7. 在Windows8.1中通过IIS发布网站产生HTTP Error 503错误的解决方案

    1.解决IIS下网站Bin目录中32位DLL不能使用,如图所示 2.解决通过IIS浏览网站,出现Http503的问题,如图所示

  8. Qt之绘制闪烁文本

    简述 根据之前的二位绘图,我们可以很轻松的进行文本的绘制,如果需要一些特效,比如:文本闪烁.我们就必须借助其它辅助类来完成. 简述 原理 实现 效果 源码 原理 主要涉及两个辅助类: QFontMet ...

  9. bug:C#线程间操作无效: 从不是创建控件" XX" 的线程访问它

    今天遇到这个问题,百度了下,把解决的方法总结出来.我们在ui线程创建的子线程操作ui控件时,系统提示错误详细信息为:线程间操作无效: 从不是创建控件“XXX”的线程访问它. 就我知道的有三种方法,先看 ...

  10. cf--------(div1)1A. Theatre Square

    A. Theatre Square time limit per test 2 seconds memory limit per test 64 megabytes input standard in ...