C++ 构造函数初始化调用顺序及类函数内部嵌套函数情况

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_38998213/article/details/83860699

C++构造函数初始化顺序

C++构造函数按下列顺序被调用:(1、2、3、4是按照优先级顺序来的!)
(1)任何虚拟基类的构造函数按照它们被继承的顺序构造;
(2)任何非虚拟基类的构造函数按照它们被继承的顺序构造;
(3)任何成员对象的构造函数按照它们声明的顺序调用;(如果成员对象有前面出现过的父类,那么还会调用此对象父类的构造函数一遍,因为第一遍(1)(2)是为了创建子类,第二遍调用是为了构造里面的成员对象。)
(4)类自己的构造函数。
  例子:

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

猜你喜欢

转载自blog.csdn.net/qq_38998213/article/details/83860699