• C++-理解构造函数、析构函数执行顺序


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

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

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

       

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

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

     

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

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

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

     

        执行结果是:

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

    (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

    编译运行环境:

    [plain] view plaincopy
    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.   
    4. $ g++ --version  
    5. 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,请勿用于任何商业用途!

  • 相关阅读:
    MySQL主从复制(7)回顾原理、企业场景部署
    MySQL主从复制(6)故障、快速配置
    *MySQL主从复制(5)实战
    MySQL主从复制(4)原理画图深入浅出
    MySQL主从复制(3)应用场景,切换不丢数据
    MySQL主从复制(2)介绍及分布式架构
    MySQL主从复制(1)DB各种同步方案
    找到小镇的法官
    最长回文子串
    权限管理
  • 原文地址:https://www.cnblogs.com/dracohan/p/3423119.html
Copyright © 2020-2023  润新知