zoukankan      html  css  js  c++  java
  • C++派生类构造函数调用顺序(详解)

    我们来看下面一段代码:

      class B1
      {
      public:
      B1(int i) {cout<<"constructing B1 "<<i<<endl;}
      };
      class B2
      {
      public:
      B2(int j) {cout<<"constructing B2 "<<j<<endl;}
      };
      class B3
      {
      public:
      B3( ){cout<<"constructing B3 *"<<endl;}
      };
      class C: public B2, public B1, public B3
      {
      public:
      C(int a, int b, int c, int d):B1(a),memberB2(d),memberB1(c),B2(b){}
      private:
      B1 memberB1;
      B2 memberB2;
      B3 memberB3;
      };
      void main( )
      { C obj(1,2,3,4); }


      运行后的结果如下:
      constructing B2 2
      constructing B1 1
      constructing B3 *
      constructing B1 3
      constructing B2 4

     constructing B3 *
      为什么会有以上的结果?
      众所周知构造函数的执行次序如下:
      调用基类构造函数,调用顺序按照他们的继承时声明的顺序。
      调用内嵌成员对象的构造函数,调用顺序按照他们在类中声明的顺序。
      派生类的构造函数体中的内容。
      析构函数的调用顺序相反。
      那么再来看以上的例子就很容易理解了。B2、B1、B3是C的基类,按照上述的顺序,我们先要构造基类,然后才是子对象,最后是其本身的构造函数所以先要执行这三个类的构造函数。在构造时按照他们在类中的顺序,首先调用B2的构造函数
      B2(int j) {cout<<"constructing B2 "<<j<<endl;}
      由于在默认参数列表
      C(int a, int b, int c, int d):B1(a),memberB2(d),memberB1(c),B2(b){}
      中,将b的值传给了B2的构造函数,b为2,故打印出:
      constructing B2 2
      接下来要构造的是B1了。显然在C的默认参数构造列表中将a的值传给了B1,
      所以打印出:
      constructing B1 1
      B3在构造时没有传递参数,调用B3( ){cout<<"constructing B3 *"<<endl;}
      打印出:
      cout<<"constructing B3 *
      这时基类的构造函数已经执行完毕,接着该处理内嵌成员对象的构造函数了。

    我们看到C类有三个对象:B1 memberB1;B2 memberB2;B3 memberB3;,按照构造函数的调用顺序,我们需要按照他们在类中声明的顺序来分别构造memberB1、memberB2、 memberB3。在默认的参数列表中,用c来构造了memberB1,用d来构造memberB2,
      故打印出:
      constructing B1 3
      constructing B2 4
      constructing B3 *
      最后调用本身的构造函数,由于函数体为空,故什么也没有打印出来。
      总结下来,我们必须明确的是当一个类继承与基类,并且自身还包含有其他类的成员对象的时候,构造函数的调用顺序为:调用基类的构造函数->调用成员对象的构造函数->调用自身的构造函数构造函数的调用次序完全不受构造函数初始化列表的表达式中的次序影响,与基类的声明次数和成员对象在函数中的声明次序有关
    再如:

    #include<iostream.h>
    class A
    {
    protected:
         char c;
    public:
         A(char ch)
         {
               c=ch;
                cout<<"c="<<c<<endl;
                cout<<"类A构造函数被调用"<<endl;
         }
         ~A()
         {
                cout<<"类A析构函数被调用"<<endl;
         }
    };
    class B
    {
    protected:
         int i;
    
    public:
         B(int j)
         {
                i=j;
                cout<<"i="<<i<<endl;
               cout<<"类B构造函数被调用"<<endl;
         }
         ~B()
         {
               cout<<"类B析构函数被调用"<<endl;
         }
    };
    class C:public A,B
    {
    private:
         int k;
    public:
         C(char ch,int ii,int kk):A(ch),B(ii),k(kk)
         {
               cout<<"k="<<k<<endl;
               cout<<"类C构造函数被调用"<<endl;
    
    }
         ~C()
         {
               cout<<"类C析构函数被调用"<<endl;
         }
    };
    void main()
    {
         C A('B',10,15);
    }

    输出结果:
    c=B
    类A构造函数被调用
    i=10
    类B构造函数被调用
    k=15
    类C构造函数被调用
    类C析构函数被调用
    类B析构函数被调用
    类A析构函数被调用

  • 相关阅读:
    mysql的数据结构
    mysql 如何在虚拟机中创建多个实例并启动
    mysql的查询语句原理
    mysql 之如何修复删除用户表
    docker之卷管理 与 卷挂载
    mysql的高可用
    python全栈脱产第35天------IPC机制、生产者消费者模型、线程、
    python全栈脱产第33天------基于udp协议的套接字、socketserver模块的使用、进程理论
    python全栈脱产第34天------开启进程的两种方式、join方法、进程对象其他相关的属性和方法、僵尸进程、孤儿进程、守护进程、互斥锁
    python全栈脱产第32天------基于tcp协议通信的套接字、模拟ssh实现远程执行命令、粘包问题
  • 原文地址:https://www.cnblogs.com/wujing-hubei/p/6659393.html
Copyright © 2011-2022 走看看