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

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

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

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

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

C++继承时构造函数和析构函数的执行顺序

继承时构造函数和析构函数的执行顺序 单一继承:先调用父类构造函数,再调用子类的构造函数多重继承:调用基类构造函数的顺序是继承时的顺序...
  • lmb1612977696
  • lmb1612977696
  • 2017-03-20 23:12:05
  • 159

C++继承中构造函数、析构函数调用顺序及虚析构函数

C++继承中构造函数、析构函数调用顺序及虚析构函数 首先说说构造函数,大家都知道构造函数里就可以调用成员变量,而继承中子类是把基类的成员变成自己的成员,那么也就是说子类在构造函数...
  • u012861978
  • u012861978
  • 2016-02-16 11:29:48
  • 1354

c++ 内存申请释放,构造函数,析构函数,执行顺序

内存释放,申请与析构,构造函数 这几个函数的执行顺序是什么,我们已经知道对于普通的对象,会先执行内存申请函数,然后执行构造函数,然后执行析构函数,最后执行内存释放函数。 但是,对于有继承关系的对象...
  • nilbooy
  • nilbooy
  • 2016-05-14 09:48:33
  • 635

总结c++类的构造函数 拷贝构造函数 析构函数 赋值运算符重载的特点以及函数调用顺序

对 c++类成员函数中的构造函数 拷贝构造函数 析构函数 赋值运算符重载的一些特点以及函数调用顺序,并附上例子,希望对大家有帮助,有错误大家可以指出来。...
  • wenqiang1208
  • wenqiang1208
  • 2016-10-18 19:04:40
  • 1398

C/C++面试题:构造函数与析构函数

构造函数与析构函数的一道小题下面程序的输出是什么?#includeusing namespace std;class TestClass{ char x; public: TestCl...
  • u010429424
  • u010429424
  • 2017-08-11 21:36:10
  • 401

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

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

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

C++ 派生类的析构函数的调用顺序为: A)  基类、派生类和对象成员类的析构函数  B)  派生类、对象成员类和基类的析构函数  C)  对象成员类、派生类和基类的析构函数     D)  ...
  • dyx810601
  • dyx810601
  • 2016-08-02 20:53:02
  • 3966
收藏助手
不良信息举报
您举报文章:浅出C++对象模型——理解构造函数、析构函数执行顺序
举报原因:
原因补充:

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