当前课程知识点:C++语言程序设计进阶 > 第七章 继承与派生 > 派生类的构造和析构 > 派生类的构造函数举例
#include <iostream> using namespace std; class Base1 {//基类Base1,构造函数有参数 public: Base1(int i) { cout << "Constructing Base1 " << i << endl; } }; class Base2 {//基类Base2,构造函数有参数 public: Base2(int j) { cout << "Constructing Base2 " << j << endl; } }; class Base3 {//基类Base3,构造函数无参数 public: Base3() { cout << "Constructing Base3 *" << endl; } }; class Derived: public Base2, public Base1, public Base3 { public: Derived(int a, int b, int c, int d): Base1(a), member2(d), member1(c), Base2(b) //此处的次序与构造函数的执行次序无关 { } private: Base1 member1; Base2 member2; Base3 member3; }; int main() { Derived obj(1, 2, 3, 4); return 0; }
大家好
欢迎回来继续学习
C++语言程序设计
接下来
我们就来看一个
既有继承
又有组合的例子
那么通过这个跟踪调试呢
我们来观察一下
构造函数的调用顺序
在这个程序中呢
我们定义了一个派生类Derived
它继承了三个基类
Base2 Base1和Base3
都是公有继承
那么继承的顺序是先Base2
再Base1 再Base3
除此而外呢
它还有三个对象成员
分别是Base1的对象
Base2的对象
和Base3的对象
这是一个既有继承
又有组合的例子
那么我们关键来看
派生类的构造函数
怎么样给基类的构造函数
传递参数
怎么样在初始化列表中
给本类对象成员指定初始化参数
要运行一下主函数
看看在构造一个对象的时候
这些相关的构造函数
它们的调用次序是什么
我们先看这个派生类对象
在这里它给Base1类
传递了一个参数a
给Base2类传递了一个参数b
我们看看Base1类
确实它的构造函数需要一个参数
Base2的构造函数
也需要一个参数
但是Base3的构造函数
它不需要参数
所以在Derived构造函数中呢
当然就没有给Base3传递参数
同样呢
我们要给它的对象成员
指定初始化需要的参数
成员member2是Base2类型的
它需要一个参数
在这里我们给它指定了
b是给它的
成员member1它是Base1的对象
它的初始化需要一个参数
这里也给它了一个c
所以我们来看
在这个
Derived的构造函数的形参表中
列出了它需要传递给
基类构造函数的参数
需要用来初始化本类对象
本类这个对象成员的参数
都列在这儿了
然后在初始化列表中呢
分配一下
每个参数分别用来做什么
给谁
但是呢
这里列的次序
跟初始化的时候
执行构造函数的次序是无关的
这里并不是对构造函数来调用
只是一个初始化列表
列出哪些初始值给谁
而执行的次序是什么样的呢
应该是按照
首先按照基类自己
在这个继承的时候
排列的次序来执行
然后执行完了这些
再执行派生类
自己的对象成员的初始化
这个执行次序呢
按照这些成员定义时候
出现的次序
现在我们来运行这个主函数
验证一下
现在进到Derived构造函数里面
看看它接下来先调用
哪个构造函数
我们看到
进到了Base2的构造函数里面
这个跟这儿的书写次序
就不一样了
我们把Base1的初始化
写在最前面
但是呢在继承的时候
Base2排在前面
所以
先进到Base2的构造函数里面
回来以后
再跟踪一个函数进去
这回进到
Base1的构造函数里面了
这两个都是基类
所以基类的构造函数
是先被执行的
好 回来以后
接下来该执行什么了呢
我们来看看
进到Base3的构造函数中了
虽然这里没有给Base3
传递参数
因为Base3的构造函数
是不需要参数的
但是它也会按照继承时候
列出来的次序被调用的
首先
都是把基类的构造函数执行完
然后回来以后
接下来走到哪儿去呢
又进到
Base1的构造函数里面去了
这个时候是为了
初始化成员对象member1
那再次进到构造函数里面
进到谁里面去了呢
进到Base2的构造函数里面了
在这儿
这是为了初始化
成员对象member2
回来
现在就剩下成员对象mnmber3
没有初始化了
它也不需要参数
所以我们再跟踪一步
看
进到Base3的构造函数里面来了
这样三个成员对象
都被初始化完成了
那这个时候呢
由于Derived构造函数
它的函数体是空的
因此这个函数也就执行完了
回到主函数
现在这个对象已经构造完成了
-导学
--导学
-继承的基本概念和语法
-第七章 继承与派生--继承的基本概念和语法习题
-继承方式
-第七章 继承与派生--继承方式
-基类与派生类类型转换
-第七章 继承与派生--基类与派生类类型转换
-派生类的构造和析构
--派生类的构造函数
--派生类的析构函数
--第七章 继承与派生--派生类的构造和析构
-派生类成员的标识与访问
--虚基类
-第七章 继承与派生--派生类成员的标识与访问
-小结
--小结
-综合实例
--第七章综合实例
-实验七
--实验七
-导学
--导学
-第八章 多态性--导学
-运算符重载
--运算符重载的规则
-第八章 多态性--运算符重载
-虚函数
--虚函数
--虚析构函数
--虚表与动态绑定
-第八章 多态性--虚函数
-抽象类
--抽象类
--第八章 多态性--抽象类
-override与final
-第八章 多态性--override与final
-小结
--第八章小结
-综合实例
--第八章综合实例
-实验八
--实验八
- 第八章讲义
-导学
--导学
-模板
--函数模板
--类模板
-第九章 模板与群体数据--模板
-线性群体
--线性群体的概念
-第九章 模板与群体数据--线性群体
-数组
--数组类模板
-链表
--链表类模板
-第九章 模板与群体数据--链表
-栈
--栈类模板
--栈类模板课后习题
--例9-9 栈的应用课后习题
-队列
--队列类模板
-第九章 模板与群体数据--队列
-排序
--排序概述
--插入排序
--选择排序
--交换排序
-第九章 模板与群体数据--排序
-查找
--查找
--查找课后习题
-小结
--小结
-综合实例
--综合实例
-实验九
--实验九
- 第九章讲义
-导学
--导学
-泛型程序设计及STL的结构
--STL简介
-第十章 泛型程序设计与C++标准模板库--泛型程序设计及STL的结构
-迭代器
--迭代器
-第十章 泛型程序设计与C++标准模板库--迭代器
-容器的基本功能与分类
-第十章 泛型程序设计与C++标准模板库--容器的基本功能与分类
-顺序容器
--顺序容器的特征
--第十章 泛型程序设计与C++标准模板库--顺序容器
-关联容器
--集合
--映射
-第十章 泛型程序设计与C++标准模板库--关联容器
-函数对象
--函数对象
--函数适配器
-算法
--算法
-小结
--第十章小结
-综合实例
--综合实例
-实验十
--实验十
- 第十章讲义
-导学
--导学
-I/O流的概念及流类库结构
-第十一章 流类库与输入/输出--I/O流的概念及流类库结构
-输出流
--输出流概述
--向文本文件输出
--向二进制文件输出
--向字符串输出
-第十一章 流类库与输入/输出--输出流
-输入流
--输入流概述
--输入流应用举例
--从字符串输入
-第十一章 流类库与输入/输出--输入流
-输入/输出流
--输入/输出流
-第十一章 流类库与输入/输出--输入/输出流
-小结
--小结
-综合实例
--综合实例
-实验十一
--实验十一
- 第十一章讲义
-导学
--第12章导学
-异常处理的思想与程序实现
-第十二章 异常处理--异常处理的思想与程序实现
-异常处理中的构造与析构
-第十二章 异常处理--异常处理中的构造与析构
-标准程序库异常处理
-第十二章 异常处理--标准程序库异常处理
-小结
--第12章小结
-综合实例
--综合实例
-实验十二
--实验十二
- 第十二章讲义