C++类继承中,基类/当前对象属性/当前对象的构造顺序
[1]中提到,规范的派生类构造函数三个要点:
- 首先创建基类对象
- 应通过成员初始化列表,创建基类对象
- 应该初始化本派生类新增的成员变量
那在构造派生类实例的过程中,其基类(以及多继承的时候多个基类)/当前对象属性/当前对象的构造顺序如何呢?
下面初步分析:
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
- 1 C++ primer plus第六版
- 2 C++手稿:封装与继承
C++类继承中,基类/当前对象属性/当前对象的构造顺序的更多相关文章
- C++//菱形继承 //俩个派生类继承同一个基类 //又有某个类同时继承俩个派生类 //成为 菱形继承 或者 钻石 继承//+解决
1 //菱形继承 2 //俩个派生类继承同一个基类 3 //又有某个类同时继承俩个派生类 4 //成为 菱形继承 或者 钻石 继承 5 6 #include <iostream> 7 #i ...
- 修改tt模板让ADO.NET C# POCO Entity Generator With WCF Support 生成的实体类继承自定义基类
折腾几天记载一下,由于项目实际需要,从edmx生成的实体类能自动继承自定义的基类,这个基类不是从edmx文件中添加的Entityobject. 利用ADO.NET C# POCO Entity Gen ...
- lua中基类和“继承机制”
基类:基类定义了所有对于派生类来说普通的属性和方法,派生类从基类继承所需的属性和方法,且在派生类中增加新的属性和方法. 继承:继承是C++语言的一种重要机制,它允许在已定义的类的基础上产生新类. lu ...
- 不可或缺 Windows Native (21) - C++: 继承, 组合, 派生类的构造函数和析构函数, 基类与派生类的转换, 子对象的实例化, 基类成员的隐藏(派生类成员覆盖基类成员)
[源码下载] 不可或缺 Windows Native (21) - C++: 继承, 组合, 派生类的构造函数和析构函数, 基类与派生类的转换, 子对象的实例化, 基类成员的隐藏(派生类成员覆盖基类成 ...
- C# 类型运算符重载在类继承中的调用测试
这是一篇晦涩难懂的片面的研究 一,简单的继承层次 class CA { } class CB : CA{ } class CC : CB{ } } void Test(CA oa){//CATest ...
- C++类继承中的构造函数和析构函数 调用顺序
思想: 在C++的类继承中,构造函数不能被继承(C11中可以被继承,但仅仅是写起来方便,不是真正的继承) 建立对象时,首先调用基类的构造函数,然后在调用下一个派生类的构造函数,依次类推: 析构对象时, ...
- 【Android进阶】为什么要创建Activity基类以及Activity基类中一般有哪些方法
现在也算是刚刚基本完成了自己的第一个商业项目,在开发的过程中,参考了不少人的代码风格,然而随着工作经验的积累,终于开始慢慢的了解到抽象思想在面向对象编程中的重要性,这一篇简单的介绍一下我的一点收获. ...
- C++中的类继承(2)派生类的默认成员函数
在继承关系里面, 在派生类中如果没有显示定义这六个成员 函数, 编译系统则会默认合成这六个默认的成员函数. 构造函数. 调用关系先看一段代码: class Base { public : Base() ...
- C++基础——类继承中方法重载
一.前言 在上一篇C++基础博文中讨论了C++最基本的代码重用特性——类继承,派生类可以在继承基类元素的同时,添加新的成员和方法.但是没有考虑一种情况:派生类继承下来的方法的实现细节并不一定适合派生类 ...
随机推荐
- python线程Example
# -*- coding:utf-8 -*- import time import pymongo from threading import Thread from Queue import Que ...
- Asp.net mvc 大文件上传 断点续传
Asp.net mvc 大文件上传 断点续传 进度条 概述 项目中需要一个上传200M-500M的文件大小的功能,需要断点续传.上传性能稳定.突破asp.net上传限制.一开始看到51CTO上的这 ...
- CSS sprites减少HTTP请求
使用CSS sprites减少HTTP请求 sprites是鬼怪,小妖精,调皮鬼的意思,初听这个高端洋气的名字我被震慑住了,一步步掀开其面纱后发觉很简单的东西,作用却很大 神马是CSS 小妖精 C ...
- 高级SQL特性
SQL SQL 必知必会·笔记<20>高级SQL特性 摘要: 约束(constraint)就是管理如何插入或处理数据库数据的规则.DBMS通过在数据库表上施加约束来实施引用完整性.1. ...
- Js中call apply函数以及this用法
this介绍: C#里this关键字的意义比较确定的.JavaScript的this关键字,随着函数使用场合不同,this的值会发生变化,感觉用法比较混乱,所以,现在是有必要整理一下的时刻了! 总结一 ...
- ORA-12520错误解决方法
ORA-12520监听程序无法为请求的服务器类型找到可用的处理程序 以下不知道是不是解决方法的方法,因为我只重启下oracle服务就好了,并没进行任何修改 引用别人的文章: 1)数据库是专用服务器,但 ...
- WordPress 4.3.1正式发布 修复了3个安全问题
WordPress 4.3.1正式发布 修复了3个安全问题! 出于安全性考虑,建议大家进行升级! WordPress 4.3.1 安全维护版本已经发布,该版本是针对之前所有版本的安全更新,强烈建议大 ...
- in和exists哪个效率高本人测试证明
in和exists哪个效率高本人测试证明 SQLSERVR语句 in和exists哪个效率高自己测试本人测试证明 最近很多人讨论in和exists哪个效率高,今天就自己测试一下 我使用的是客户的数据库 ...
- 使用js加载图像和setDataXML()加载数据
使用js加载图像和setDataXML()加载数据 前面一篇对FusionCharts进行了一个简单的介绍,而且建立了我们第一个图形,但是那个是在HTML中使用<OBJECT>和<E ...
- C# 网络编程之最简单浏览器实现
最近学习C#网络编程的HTTP协议编程,HTTP即Hypertext Transfer Protocol的缩写,意为:超文本传输协议. 其中与HTTP相关的知识主要有六个类的知识,分别是 (1).Ht ...