[1]中提到,规范的派生类构造函数三个要点:

  1. 首先创建基类对象
  2. 应通过成员初始化列表,创建基类对象
  3. 应该初始化本派生类新增的成员变量

那在构造派生类实例的过程中,其基类(以及多继承的时候多个基类)/当前对象属性/当前对象的构造顺序如何呢?

下面初步分析:

1 不显式调用基类构造函数

C继承B1和B2

#include<iostream>
using namespace std;
class B1
{
public:
B1(){ cout<<"B1"<<endl;}
};
class B2
{
public:
B2(){cout<<"B2"<<endl;}
};
class C:public B1,public B2
{
public:
C(){cout<<"C"<<endl;}
};
int main()
{
C obj;
return 0;
}
/*output
B1
B2
C
*/

其中,冒号指出C的基类是B1和B2,public限定符指出B1和B2都是公有基类,我们称之为公有派生[1]。

公有派生中,基类的公有成员(成员变量、成员方法)变成了派生类的公有成员。基类的私有成员变成了派生类的私有成员,但是不能直接访问,只能借助基类的public和protected方法访问。

这时,程序将使用基类默认构造函数。

也就是说C的写法相当于在成员初始化列表调用基类的默认构造函数:C():B1(),B2(){cout<<"C"<<endl;}

  • B1和B2的构造顺序只和继承的顺序有关,和成员初始化列表中的顺序无关

调整继承顺序class C:public B2,public B1,输出顺序为B2 B1.而修改成员初始化列表中的顺序没有效果。

2 显式调用基类构造函数

同样的,B1和B2的构造顺序只和继承的顺序有关,和成员初始化列表中的顺序无关

class B1
{
public:
B1(){ cout<<"B1"<<endl;}
B1(int i){ cout<<"B1:"<<i<<endl;}
};
class B2
{
public:
B2(){cout<<"B2"<<endl;}
B2(int i){ cout<<"B2:"<<i<<endl;}
};
class C:public B2,public B1
{
public:
C():B1(10),B2(20){cout<<"C"<<endl;}
};
int main()
{
C obj;
return 0;
}
/*output
B2:20
B1:10
C
*/

更进一步可以把C中构造函数参数作为实参传递给基类构造函数:

C(int x,int y):B1(x),B2(y){cout<<"C"<<endl;}

3 封闭类

有成员对象的类称为封闭类,这是对象组合的一种实现方式[2]。

修改C为:

class C:public B2,public B1
{
private:
int x;
B1 memberb1;
B2 memberb2;
public:
C():B1(10),B2(20){cout<<"C"<<endl;}
};
/*output
B2:20
B1:10
B1
B2
C
*/
  • 构造子类实例过程中,依次进行如下构造:

    • 构造基类
    • 构造当前派生类的成员对象
    • 构造当前派生类(执行自己的构造函数)

3.1 对当前对象属性使用成员初始化列表语法

当前对象属性就是成员对象

class C:public B2,public B1
{
private:
int x;
B1 memberb1;
B2 memberb2;
public:
C():B1(10),B2(20),memberb1(1),memberb2(2){cout<<"C"<<endl;}
};
/*output
B2:20
B1:10
B1:1
B2:2
C
*/

和基类很相似。

在成员初始化列表,如果不显式调用成员对象的构造函数,程序就会调用默认构造函数。显式调用,程序就会调用你指定的构造函数。

成员对象之间的构造顺序之和声明顺序有关,和在Member Initialization List中的顺序无关。

当然,也可以不指定初始化列表,在构造函数中再进行成员对象的赋值,这会导致成员对象被构造多次。 更重要的是,因为常量类型、引用类型的成员不接受赋值,它们只能在初始化列表中进行初始化。[2]

到这里,基类/当前对象属性/当前对象的构造顺序终于搞清楚了。

Reference

C++类继承中,基类/当前对象属性/当前对象的构造顺序的更多相关文章

  1. C++//菱形继承 //俩个派生类继承同一个基类 //又有某个类同时继承俩个派生类 //成为 菱形继承 或者 钻石 继承//+解决

    1 //菱形继承 2 //俩个派生类继承同一个基类 3 //又有某个类同时继承俩个派生类 4 //成为 菱形继承 或者 钻石 继承 5 6 #include <iostream> 7 #i ...

  2. 修改tt模板让ADO.NET C# POCO Entity Generator With WCF Support 生成的实体类继承自定义基类

    折腾几天记载一下,由于项目实际需要,从edmx生成的实体类能自动继承自定义的基类,这个基类不是从edmx文件中添加的Entityobject. 利用ADO.NET C# POCO Entity Gen ...

  3. lua中基类和“继承机制”

    基类:基类定义了所有对于派生类来说普通的属性和方法,派生类从基类继承所需的属性和方法,且在派生类中增加新的属性和方法. 继承:继承是C++语言的一种重要机制,它允许在已定义的类的基础上产生新类. lu ...

  4. 不可或缺 Windows Native (21) - C++: 继承, 组合, 派生类的构造函数和析构函数, 基类与派生类的转换, 子对象的实例化, 基类成员的隐藏(派生类成员覆盖基类成员)

    [源码下载] 不可或缺 Windows Native (21) - C++: 继承, 组合, 派生类的构造函数和析构函数, 基类与派生类的转换, 子对象的实例化, 基类成员的隐藏(派生类成员覆盖基类成 ...

  5. C# 类型运算符重载在类继承中的调用测试

    这是一篇晦涩难懂的片面的研究 一,简单的继承层次 class CA { } class CB : CA{ } class CC : CB{ } } void Test(CA oa){//CATest ...

  6. C++类继承中的构造函数和析构函数 调用顺序

    思想: 在C++的类继承中,构造函数不能被继承(C11中可以被继承,但仅仅是写起来方便,不是真正的继承) 建立对象时,首先调用基类的构造函数,然后在调用下一个派生类的构造函数,依次类推: 析构对象时, ...

  7. 【Android进阶】为什么要创建Activity基类以及Activity基类中一般有哪些方法

    现在也算是刚刚基本完成了自己的第一个商业项目,在开发的过程中,参考了不少人的代码风格,然而随着工作经验的积累,终于开始慢慢的了解到抽象思想在面向对象编程中的重要性,这一篇简单的介绍一下我的一点收获. ...

  8. C++中的类继承(2)派生类的默认成员函数

    在继承关系里面, 在派生类中如果没有显示定义这六个成员 函数, 编译系统则会默认合成这六个默认的成员函数. 构造函数. 调用关系先看一段代码: class Base { public : Base() ...

  9. C++基础——类继承中方法重载

    一.前言 在上一篇C++基础博文中讨论了C++最基本的代码重用特性——类继承,派生类可以在继承基类元素的同时,添加新的成员和方法.但是没有考虑一种情况:派生类继承下来的方法的实现细节并不一定适合派生类 ...

随机推荐

  1. 一键部署mono 免费空间

    一键部署mono 免费空间支持c# 再也不担心伙食费换空间了 一直以来 部署mono 都是很头疼的事情 因为是我在是不熟悉非win环境,今天偶然发现这个项目,挺好的,分享下 https://githu ...

  2. Carmichael Numbers - PC110702

    欢迎访问我的新博客:http://www.milkcu.com/blog/ 原文地址:http://www.milkcu.com/blog/archives/uva10006.html 原创:Carm ...

  3. AHOI1997彩旗飘飘 VIJOS1097合并果子(noip2007)

    AHOI彩旗飘飘 这是一题类似于排列组合的题目吧...递推状态 数组f[100][100][100][2];表示红旗数目,黄旗数目,颜色改变的次数,末尾的旗的颜色(0为黄,1为红) 之后就是如何写递推 ...

  4. MongoDB学习(翻译2)

    C#驱动之LINQ教程 介绍 本教程涵盖了1.8发布版本对linq查询的支持. 开始本教程之前,你应该至少阅读下C#驱动教程关于C#驱动的介绍 快速开始 首先,添加下面命名空间到您的程序中: usin ...

  5. 绘制基本图形和线型(StrokeStyle)的设置详解

    绘制基本图形和线型(StrokeStyle)的设置详解 目前,在博客园上,相对写得比较好的两个关于Direct2D的教程系列,分别是万一的Direct2D系列和zdd的Direct2D系列.有兴趣的网 ...

  6. 跨站请求伪造(Cross Site Request Forgery (CSRF))

    跨站请求伪造(Cross Site Request Forgery (CSRF)) 跨站请求伪造(Cross Site Request Forgery (CSRF)) 跨站请求伪造(Cross Sit ...

  7. SQL Server 2014新特性:五个关键点带你了解Excel下的Data Explorer

    SQL Server 2014新特性:五个关键点带你了解Excel下的Data Explorer Data Explorer是即将发布的SQL Server 2014里的一个新特性,借助这个特性讲使企 ...

  8. 挖一下插件v1.5版本发布

    Chrome图片下载插件,支持网页截屏 v.1.5更新说明: 1.增加下载图片按日期分类保存选项,便于管理,用户可根据需要开启/关闭此设置 2.增加网页图片采集快捷键: (1)采集页面图片(Ctrl+ ...

  9. 欢迎关注我的微信公众账号:Linux技巧(微信号:irefactoring),一起学习Linux知识~~~

    最近很少写博客了,一方面是近期工作比较繁忙,第二是把精力都放在GitHub和读源码去了. 申请了一个微信公众账号:Linux技巧 微信ID:irefactoring(意思是爱重构) ========= ...

  10. nginx+apache+mysql+php+memcache+squid搭建集群web环境

    服务器的大用户量的承载方案 一.前言 二.编译安装 三. 安装MySQL.memcache 四. 安装Apache.PHP.eAccelerator.php-memcache 五. 安装Squid 六 ...