我们来看下面一段代码:

  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(,,,); }

运行后的结果如下:
  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',,);
}

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

C++派生类构造函数调用顺序(详解)的更多相关文章

  1. 3.7 C++派生类构造函数调用规则

    参考:http://www.weixueyuan.net/view/6364.html 总结: 派生类构造函数可以自动调用基类的默认构造函数而无需显式调用. 生类构造函数可以自动调用基类的默认构造函数 ...

  2. Java基础-DButils工具类(QueryRunner)详解

    Java基础-DButils工具类(QueryRunner)详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 如果只使用JDBC进行开发,我们会发现冗余代码过多,为了简化JDBC ...

  3. java初始化构造函数调用顺序

    类初始化时构造函数调用顺序: (1)初始化对象的存储空间为零或null值:  (2)调用父类构造函数:  (3)按顺序分别调用类成员变量和实例成员变量的初始化表达式:  (4)调用本身构造函数. 例子 ...

  4. Delphi中TStringList类常用属性方法详解

    TStrings是一个抽象类,在实际开发中,是除了基本类型外,应用得最多的. 常规的用法大家都知道,现在来讨论它的一些高级的用法. 先把要讨论的几个属性列出来: 1.CommaText 2.Delim ...

  5. vxWorks/BootROM Imageq启动顺序详解

    vxWorks/BootROM Imageq启动顺序详解 VxWorks image     分为在ROM中运行和在RAM中运行两种,两者启动顺序的区别在于sysInit()函数的调用,该函数在RAM ...

  6. Python的Django框架中forms表单类的使用方法详解

    用户表单是Web端的一项基本功能,大而全的Django框架中自然带有现成的基础form对象,本文就Python的Django框架中forms表单类的使用方法详解. Form表单的功能 自动生成HTML ...

  7. Kotlin——中级篇(一):类(class)详解

    在任何一门面向对象编程的语言里,类(class)是非常基础.但也是非常重要的一项组成,通俗的说就是万般皆对象,而所说的对象就是我们生成的类.Kotlin也是如此,下面详细为大家介绍Kotlin中的类的 ...

  8. Java AtomicInteger类的使用方法详解_java - JAVA

    文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 首先看两段代码,一段是Integer的,一段是AtomicInteger的,为以下: public class Samp ...

  9. Tomcat5的web应用启动顺序详解

    Tomcat5的web应用启动顺序详解 [收藏此页] [打印]   作者:佚名  2007-07-17 内容导航: 第1页   [IT168技术文档]摘要: 应用Tomcat对于我们来讲实在是司空见惯 ...

随机推荐

  1. 为eclipse添加源代码

    看到这个页面,直接点击 红色区域 attach source 关联源代码,进入到如下页面: 点击第二个选择外部的路径,点击导入文件夹,也就是解压出来的src文件夹(不建议直接导整个jar包,虽然也可以 ...

  2. 20155238 2016-2017-2 《Java程序设计》第二周学习总结

    教材学习内容总结 java基本类型:整数,字节,浮点数,字符 //"单行批注" */"单行批注" 变量 "驼峰式命命法" int age0f ...

  3. msfconsole 无法启动,解决办法

    今天突然碰上kali msfconsole 无法启动,经过查找资料,现已成功解决该问题,现将解决办法整理如下: service postgresql start # 启动数据库服务 msfdb ini ...

  4. 20155327预备作业3:Linux安装及命令入门

    20155327预备作业3:Linux安装及命令入门 安装Linux操作系统 由于之前安装过所以这里就不再赘述了 掌握Linux命令的学习方法 学习路径: 常用Ubuntu快捷键: CTRL+ALT+ ...

  5. MySQL下查看和赋予权限

    磨砺技术珠矶,践行数据之道,追求卓越价值 回到上一级页面: PostgreSQL杂记页     回到顶级页面:PostgreSQL索引页 [作者 高健@博客园  luckyjackgao@gmail. ...

  6. python基础学习1-字典的使用

    id_db={1:"wh" ,2:"wx" ,3:{1:"a",2:"b",3:"c"} ,4:[& ...

  7. P3702 [SDOI2017]序列计数

    P3702 [SDOI2017]序列计数 链接 分析: 首先可以容斥掉,用总的减去一个质数也没有的. 然后可以dp了,f[i][j]表示到第i个数,和在模p下是j的方案数,矩阵快速幂即可. 另一种方法 ...

  8. pycharm导入路径问题

    博主在导入自定义模块式出现模块下有红色波浪线,如下: 例如from conf import setting 导入时会从当前目录下找找到youkuClient就不会再往下找了,所以引入模块的路径不能夸路 ...

  9. 【JUC源码解析】SynchronousQueue

    简介 SynchronousQueue是一种特殊的阻塞队列,该队列没有容量. [存数据线程]到达队列后,若发现没有[取数据线程]在此等待,则[存数据线程]便入队等待,直到有[取数据线程]来取数据,并释 ...

  10. 使用ASP.NET Identity以手机短信实现双重验证

    这篇文章将展示怎么使用SMS短信启动双重验证 创建一个ASP.NET 5项目 一开始,使用Visual studio 2015创建一个新的ASP.NET Web应用程序: 在下一步中选择ASP.NET ...