浅出C++对象模型——理解构造函数、析构函数执行顺序

原创 2013年04月11日 21:04:08
   

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

  

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

 

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

 

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

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

#include <iostream>
using namespace std;

class Foo
{
public:
        Foo() { cout << "Foo constructor" << endl; }
        Foo(const Foo &foo) { cout << "Foo copy constructor" << endl; }
        ~Foo() { cout << "Foo deconstructor" << endl; }
};

class Bar
{
public:
        Bar() { cout << "Bar constructor" << endl; }
        Bar(const Bar &bar) { cout << "Bar copy constructor" << endl; }
        ~Bar() { cout << "Bar deconstructor" << endl; }
};

class Base
{
public:
        Base() { cout << "Base constructor" << endl; }
        ~Base() { cout << "Base deconstructor" << endl; }
};

class Derived : public Base
{
public:
        Derived() { cout << "Derived constructor without arguments" << endl; }
        Derived(const Foo &foo, const Bar &bar);
        Derived(const Bar &bar, const Foo &foo);
        ~Derived() { cout << "Derived deconstructor" << endl; }

private:
        Foo m_foo;
        Bar m_bar;
};

Derived::Derived(const Foo &foo, const Bar &bar) :
        m_foo(foo),
        m_bar(bar)
{
        cout << "Derived constructor with argument[Foo foo, Bar bar] passed by references" << endl;
}

Derived::Derived(const Bar &bar, const Foo &foo) :
        m_bar(bar),
        m_foo(foo)
{
        cout << "Derived constructor with argument[Bar bar, Foo foo] passed by references" << endl;
}

int main (int argc, char** argv)
{
        Foo foo;
        Bar bar;

        cout << "test case 1:" << endl;
        Derived deri_1;  //  (1)

        cout << "test case 2:" << endl;
        Derived deri_2(foo, bar);   //  (2)

        cout << "test case 3:" << endl;
        Derived deri_3(bar, foo);   //  (3)

        cout << "test case end" << endl;

        return 0;
}

    执行结果是:


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

(1) 创建对象foobar ,执行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


编译运行环境:

$ uname -a
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

$ g++ --version
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,请勿用于任何商业用途!

Author: Gary Gao( garygaowork[at]gmail.com) 关注互联网、分布式、高性能、NoSQL、自动化、软件团队

支持我的工作:  https://me.alipay.com/garygao




版权声明:本文为博主(微博@Gary的影响力)原创文章,未经博主允许不得转载。博客地址:http://garyelephant.me https://blog.csdn.net/gaoyingju/article/details/8790233

C++多个类中构造函数与析构函数的调用顺序

C++中有一个很重要的法则:使用构造函数创建对象的顺序与使用析构函数释放对象的顺序相反。对于一些C++的初学者来说,这是一条有点费解的法则,那么该怎么理解和清晰的表现出来呢?下面我们通过程序来体现一下...
  • casky237
  • casky237
  • 2017年01月14日 22:33
  • 1285

浅谈C++对象模型——理解构造函数、析构函数执行顺序

本文主要说明对象创建时构造函数的执行顺序,对象成员的初始化顺序;对象销毁时析构函数的执行顺序,对象成员的销毁顺序。         “对象的构造从类层次的最根处开始,在每一层中,首先调...
  • jiguang0455
  • jiguang0455
  • 2013年04月12日 14:49
  • 552

总结笔记-c++成员变量、构造函数以及析构函数的执行顺序

在我的之前的博客http://blog.csdn.net/caoyan_12727/article/details/52356844有提到c++各种变量的初始化规则,本文将总结c++中涉及到的各种变量...
  • caoyan_12727
  • caoyan_12727
  • 2016年09月03日 12:14
  • 1274

C++派生类的构造函数和析构函数执行顺序及其构造形式

在C++程序员的面试中,经常会出现派生类与基类的构造函数、析构函数的执行顺序。其实这是一个很基本的问题,没有什么难度,只需要记住就OK了。      1.派生类的构造函数和析构函数的执行顺序   ...
  • u013951778
  • u013951778
  • 2015年08月29日 09:46
  • 1295

c++学习笔记5,多重继承中派生类的构造函数与析构函数的调用顺序(二)

现在来测试一下在多重继承,虚继承
  • guang_jing
  • guang_jing
  • 2014年05月21日 20:32
  • 1635

关于基类和派生类的构造函数和析构函数的执行顺序问题

C++ 派生类的析构函数的调用顺序为: A)  基类、派生类和对象成员类的析构函数  B)  派生类、对象成员类和基类的析构函数  C)  对象成员类、派生类和基类的析构函数     D)  ...
  • dyx810601
  • dyx810601
  • 2016年08月02日 20:53
  • 3966

C++构造函数和析构函数的总结

C++是面向对象的编程语言,在定义类的时候,离不开构造和析构函数。类中同类同名的成员函数称为构造函数,主函数中初始化一个对象时,如果有传入数据,其实是传入到构造函数的形参中。...
  • ladybai
  • ladybai
  • 2016年03月10日 14:51
  • 4332

c++构造函数和析构函数的区别?

构造函数: 什么是构造函数?通俗的讲,在类中,函数名和类名相同的函数称为构造函数。它的作用是在建立一个对象时,作某些初始化的工作(例如对数据赋予初值)。C++允许同名函数,也就允许在一个类中有多个构...
  • xinsong520
  • xinsong520
  • 2016年08月25日 18:35
  • 745

深入理解C++对象模型之构造函数

学习C++的同学一般都知道有构造函数这个东西,我相信很多同学的理解就是构造函数是用来初始化类成员的,是的,构造函数的本质确实是这样的,但很多同学会有以下两个误解:(1)任何class如果没有定义任何构...
  • qq_26849233
  • qq_26849233
  • 2017年04月24日 11:21
  • 209

C++类的构造函数与析构函数

C++中每个类都有其构造与析构函数,它们负责对象的创建和对象的清理和回收,即使我们不写这两个,编译器也会默认为我们提供这些构造函数。下面仍然是通过反汇编的方式来说明C++中构造和析构函数是如何工作的。...
  • lanuage
  • lanuage
  • 2016年06月29日 22:11
  • 3535
收藏助手
不良信息举报
您举报文章:浅出C++对象模型——理解构造函数、析构函数执行顺序
举报原因:
原因补充:

(最多只允许输入30个字)