当前课程知识点:基于Linux的C++ >  第九讲 类与对象 >  9.11 继承(三) >  LinuxCPP0911

返回《基于Linux的C++》慕课在线视频课程列表

LinuxCPP0911在线视频

LinuxCPP0911

下一节:LinuxCPP0912

返回《基于Linux的C++》慕课在线视频列表

LinuxCPP0911课程教案、知识点、字幕

对于一个派生类

它的构造函数和析构函数的执行

有一些特别的限定

构造函数 它的执行顺序是这么规定的

首先 它要调用基类的构造函数

因为它是一个派生 有一个层次树嘛

所以它的基类构造函数的调用顺序

是与基类在这个派生类中继承的顺序

是相关的 完全一样

基类在派生类里边

它是按照什么样的继承顺序来的

那么它的构造函数

就按照什么样的顺序来构造

所以说 B类继承A类 C类继承B类

那么它构造的时候首先调用的是

A类的构造函数 然后调用B类的构造函数

然后才能调用C类的构造函数

首先调用基类的构造函数

第二个 调用派生类的新增数据对象的构造函数

如果派生类里面你增加了一个数据对象

这个数据对象本身是类的一个对象

那么这个对象也有构造函数

所以完成基类构造函数之后

它就会调用这些成员的构造函数

来去构造它的所有的成员

这个构造的顺序和这些对象

在派生类里边它的定义顺序是一样的

你先定义哪个 就先构造哪个

因为它的内存里边就按照这个顺序排的

它构造的时候

就对那个数据区域进行初始化

它肯定一个接着一个去做

所以颠倒做肯定不如顺序做方便

也不如那个效率高

所以啊 它就跟那个顺序是相同的

最后 它才是调用派生类自己的构造函数

它是按照这样一个方式去构造的

如果这些量写在初始化列表里边

它就用初始化列表里面的数据去构造它

最后调用我们的函数体

构造函数的函数体

这就是派生类的构造函数的执行顺序

析构函数是反过来的

首先 它调用派生类的析构函数

先把派生类的新增那些东西给它消掉

然后调用派生类的

新增的对象成员的析构函数

调用的顺序刚好和它的构造顺序是相反的

你如果派生类中有三个数据成员

a、b、c 都是类的对象

那么构造的时候是按照a、b、c的顺序

析构的时候就是c、b、a的顺序

一个接着一个地来

当把所有这些新增数据成员全部析构之后

它才能够调用基类的析构函数

如果它的继承层次是A、B、C

那么它析构的时候就是C、B、A

还是倒过来的

这个就是派生类的构造函数

与析构函数的执行顺序

同学们一定要深刻地理解这一点

否则的话你的程序就有可能有问题

类的赋值兼容性非常重要

因为我们在写面向对象的程序的时候

我们实际上是建构了一个类库的层次

而我们操纵这个类库层次的时候

我们往往会使用指向基类的一个指针

或者是一个基类的一个引用

公有派生的时候

任何基类的对象可以出现的位置

都可以用派生类的对象来代替

这保证了广泛的赋值兼容性

为我们编程提供极大的灵活性

这是必不可少的一个东西

涉及到三种情况

一个 可以将一个派生类的对象

赋值给一个基类的对象

这个时候它仅赋值它的基类部分

可以赋值 但有一些信息丢了

用派生类的对象

来初始化一个基类的一个引用的时候

我们仅能操作它的基类部分

一样地 一个基类的一个引用

它也只能引用它的基类的那一部分的数据

我们把一个派生类的对象初始化给它

那它引用的仍然是它的基类的那一小部分

所有的派生类数据它是访问不到的

看不见 这是非常重要的

将指向基类的指针

指向一个派生类的对象的时候

我们也仅能引领它的基类部分

指针也一样

你只能操作它的目标基类的那一部分

后续的那一部分你访问不到的

也就是说不管怎么样

当你把这个派生类的对象赋值为基类对象的时候

要么是赋值基类的部分

要么是只能操作那一部分

要么是只能引领它的那一部分

派生类的那个部分都没有办法去处理的

特别注意这一条

保护派生和私有派生

本身因为它的访问控制的原因

是不允许你直接赋值的

所以这种时候

它就完全地打破了我们类继承的层次

它的那个编程的灵活性

我们在设计这个类库继承层次的时候

需要的就是这个将派生类的对象

或派生类的引用

或者指向派生类的指针

来赋值给一个基类的对象、一个基类的引用、

一个指向基类的指针

如果缺了这个类的赋值兼容性

那么实际上 面向对象的这个继承的架构

它的好处就已经取消了一大部分

所以真正地派生的时候

使用保护派生和私有派生场合是极少极少的

绝大多数情况下我们都应该公有派生

你明确了 我们应该单继承、公有派生

这是写面向对象程序中

保证自己不犯错误的最简单的方式

反正这种方式能够解决任何问题

那不就行了嘛 我们看这样一个例子

我定义一个基类class Base

它有构造函数 有一个Print函数

我们要打印它的数据

定义了一个保护的数据成员str_a

然后有一个派生类classDerived

公有派生publicBase 公有派生下来

当然了 它有自己的构造函数

有个Derived(strings1,strings2)

特别需要说明的就是

我们的派生类构造函数里边

首先要构造它的基类的部分

而这个基类的构造函数怎么构造呢

就应该写在这个构造函数的

初始化列表里边

要写在这个构造函数的初始化列表里边

重要的事情说三遍

要写在这个类的构造函数的初始化列表里边

用类名字Base(s1)

其实调用的就是基类的构造函数

来构造基类的那一部分

构造完 然后构造派生类的自有对象 str_b

那个也是protected的string

string是标准模板库里面

替我们提供的一个类——string类

我们前面解释过 按照这个模式

这个Base只能写初始化列表里边

str_b倒是可以写在花括号体里边

但是那个写法会导致两次构造 效率降低了

所以也应该写在这个初始化列表里边

Print是它派生类里边提供的函数

输出的格式就和刚才那个就不一样了

接下来就看主函数的实现

Derived d1 构造一个派生类的对象d1

然后我定义一个基类的对象

用d1去构造它 这个构造是个拷贝构造

因为我们传的是一个d1的对象

把一个派生类的一个对象

传给一个基类的对象 然后构造它

它就要拷贝那个派生类中的那个基类部分

把它拷贝给它的基类那个对象 b1

所以呢 它要调用的就是一个拷贝构造函数

我们派生类到基类

只会复制它的基类的那个部分

所以你在d1上面调用Print

打印的将是“Hello World”

在b1上面调用 打印的将是“Hello”

因为它只构造那个“Hello”那个串

而不会复制我们的“World”

那个第二个字串 特别注意这一点

当我们使用这个Base的一个引用的时候

定义b2 然后把它初始化成d1

那就是b2将引用是d1

但是因为这个引用的型

它实际上是一个Base 所以它实际上

只能引用d1这个对象的那个基类部分

所以我们在d1上面调Print

当然还是输出“Hello World”

在b2上面调用Print

当然仍然只能输出“Hello”

如果是一个指向基类的一个指针b3

我把它初始化成d1的地址

在这种情况下边 我们引领b3的Print

打印出来的仍然是“Hello”

因为我们只能引领d1对象的基类部分

访问不到“World”那个字符串的

这是类的赋值兼容性

基于Linux的C++课程列表:

第一讲 C/C++基本语法元素

-1.1 提纲

--LinuxCPP0101

-1.2 程序设计的基本概念

--LinuxCPP0102

-1.3 简单C/C++程序介绍

--LinuxCPP0103

-1.4 程序设计的基本流程

--LinuxCPP0104

-1.5 基本语法元素

--LinuxCPP0105

-1.6 程序设计风格

--LinuxCPP0106

-1.7 编程实践

--LinuxCPP0107

-第一讲 C/C++基本语法元素--编程实践提交入口

第二讲 程序控制结构

-2.1 提纲

--LinuxCPP0201

-2.2 结构化程序设计基础

--LinuxCPP0202

-2.3 布尔数据

--LinuxCPP0203

-2.4 分支结构

--LinuxCPP0204

-2.5 break语句

--LinuxCPP0205

-2.6 循环结构

--LinuxCPP0206

-2.7 编程实践

--LinuxCPP0207

-第二讲 程序控制结构--编程实践提交入口

第三讲 函数

-3.1 提纲

--LinuxCPP0301

-3.2 函数声明、调用与定义

--LinuxCPP0302

-3.3 函数调用栈框架

--LinuxCPP0303

-3.4 编程实践

--LinuxCPP0304

-第三讲 函数--编程实践提交入口

第四讲 算法

-4.1 提纲

--LinuxCPP0401

-4.2 算法概念与特征

--LinuxCPP0402

-4.3 算法描述

--LinuxCPP0403

-4.4 算法设计与实现

--LinuxCPP0404

-4.5 递归算法(一)

--LinuxCPP0405

-4.6 递归算法(二)

--LinuxCPP0406

-4.7 容错与计算复杂度

--LinuxCPP0407

-4.8 编程实践

--LinuxCPP0408

-第四讲 算法--编程实践提交入口

第五讲 程序组织与开发方法

-5.1 提纲

--LinuxCPP0501

-5.2 库与接口

--LinuxCPP0502

-5.3 随机数库(一)

--LinuxCPP0503

-5.4 随机数库(二)

--LinuxCPP0504

-5.5 作用域与生存期

--LinuxCPP0505

-5.6 典型软件开发流程(一)

--LinuxCPP0506

-5.7 典型软件开发流程(二)

--LinuxCPP0507

-5.8 编程实践

--LinuxCPP0508

-第五讲 程序组织与开发方法--编程实践提交入口

第六讲 复合数据类型

-6.1 提纲

--LinuxCPP0601

-6.2 字符

--LinuxCPP0602

-6.3 数组(一)

--LinuxCPP0603

-6.4 数组(二)

--LinuxCPP0604

-6.5 结构体

--LinuxCPP0605

-6.6 编程实践

--LinuxCPP0606

-第六讲 复合数据类型--编程实践提交入口

第七讲 指针与引用

-7.1 提纲

--LinuxCPP0701

-7.2 指针基本概念

--LinuxCPP0702

-7.3 指针与函数

--LinuxCPP0703

-7.4 指针与复合数据类型(一)

--LinuxCPP0704

-7.5 指针与复合数据类型(二)

--LinuxCPP0705

-7.6 字符串

--LinuxCPP0706

-7.7 动态存储管理(一)

--LinuxCPP0707

-7.8 动态存储管理(二)

--LinuxCPP0708

-7.9 引用

--LinuxCPP0709

-7.10 编程实践

--LinuxCPP0710

-第七讲 指针与引用--编程实践提交入口

第八讲 链表与程序抽象

-8.1 提纲

--LinuxCPP0801

-8.2 数据抽象(一)

--LinuxCPP0802

-8.3 数据抽象(二)

--LinuxCPP0803

-8.4 链表(一)

--LinuxCPP0804

-8.5 链表(二)

--LinuxCPP0805

-8.6 链表(三)

--LinuxCPP0806

-8.7 链表(四)

--LinuxCPP0807

-8.8 函数指针(一)

--LinuxCPP0808

-8.9 函数指针(二)

--LinuxCPP0809

-8.10 抽象链表(一)

--LinuxCPP0810

-8.11 抽象链表(二)

--LinuxCPP0811

-8.12 编程实践

--LinuxCPP0812

-第八讲 链表与程序抽象--编程实践提交入口

第九讲 类与对象

-9.1 提纲

--LinuxCPP0901

-9.2 程序抽象与面向对象

--LinuxCPP0902

-9.3 类类型

--LinuxCPP0903

-9.4 对象(一)

--LinuxCPP0904

-9.5 对象(二)

--LinuxCPP0905

-9.6 类与对象的成员(一)

--LinuxCPP0906

-9.7 类与对象的成员(二)

--LinuxCPP0907

-9.8 类与对象的成员(三)

--LinuxCPP0908

-9.9 继承(一)

--LinuxCPP0909

-9.10 继承(二)

--LinuxCPP0910

-9.11 继承(三)

--LinuxCPP0911

-9.12 多态(一)

--LinuxCPP0912

-9.13 多态(二)

--LinuxCPP0913

-9.14 编程实践

--LinuxCPP0914

-第九讲 类与对象--编程实践提交入口

第十讲 操作符重载

-10.1 提纲

--LinuxCPP1001

-10.2 四则运算符重载(一)

--LinuxCPP1002

-10.3 四则运算符重载(二)

--LinuxCPP1003

-10.4 关系与下标操作符重载

--LinuxCPP1004

-10.5 赋值操作符重载(一)

--LinuxCPP1005

-10.6 赋值操作符重载(二)

--LinuxCPP1006

-10.7 赋值操作符重载(三)

--LinuxCPP1007

-10.8 赋值操作符重载(四)

--LinuxCPP1008

-10.9 赋值操作符重载(五)

--LinuxCPP1009

-10.10 流操作符重载(一)

--LinuxCPP1010

-10.11 流操作符重载(二)

--LinuxCPP1011

-10.12 流操作符重载(三)

--LinuxCPP1012

-10.13 操作符重载总结

--LinuxCPP1013

-10.14 编程实践

--LinuxCPP1014

-第十讲 操作符重载--编程实践提交入口

第十一讲 泛型编程

-11.1 提纲

--LinuxCPP1101

-11.2 泛型编程概览

--LinuxCPP1102

-11.3 异常处理机制(一)

--LinuxCPP1103

-11.4 异常处理机制(二)

--LinuxCPP1104

-11.5 运行期型式信息(一)

--LinuxCPP1105

-11.6 运行期型式信息(二)

--LinuxCPP1106

-11.7 模板与型式参数化

--LinuxCPP1107

-11.8 题外话:术语翻译

--LinuxCPP1108

-11.9 泛型编程实践(一)

--LinuxCPP1109

-11.10 泛型编程实践(二)

--LinuxCPP1110

-11.11 泛型编程实践(三)

--LinuxCPP1111

-11.12 泛型编程实践(四)

--LinuxCPP1112

-11.13 泛型编程实践(五)

--LinuxCPP1113

-11.14 泛型编程实践(六)

--LinuxCPP1114

-11.15 泛型编程实践(七)

--LinuxCPP1115

-11.16 泛型编程实践(八)

--LinuxCPP1116

-11.17 泛型编程实践(九)

--LinuxCPP1117

-11.18 泛型编程实践(十)

--LinuxCPP1118

-11.19 编程实践

--LinuxCPP1119

-第十一讲 泛型编程--编程实践提交入口

第十二讲 Linux系统编程基础

-12.1 提纲

--LinuxCPP1201

-12.2 程序执行环境(一)

--LinuxCPP1202

-12.3 程序执行环境(二)

--LinuxCPP1203

-12.4 程序执行环境(三)

--LinuxCPP1204

-12.5 程序执行环境(四)

--LinuxCPP1205

-12.6 输入输出(一)

--LinuxCPP1206

-12.7 输入输出(二)

--LinuxCPP1207

-12.8 文件系统

--LinuxCPP1208

-12.9 设备

--LinuxCPP1209

-12.10 库(一)

--LinuxCPP1210

-12.11 库(二)

--LinuxCPP1211

-12.12 makefile文件(一)

--LinuxCPP1212

-12.13 makefile文件(二)

--LinuxCPP1213

-12.14 makefile文件(三)

--LinuxCPP1214

-12.15 编程实践

--LinuxCPP1215

-第十二讲 Linux系统编程基础--编程实践提交入口

第十三讲 进程编程

-13.01 提纲

--LinuxCPP1301

-13.02 进程基本概念

--LinuxCPP1302

-13.03 信号

--LinuxCPP1303

-13.04 进程管理(一)

--LinuxCPP1304

-13.05 进程管理(二)

--LinuxCPP1305

-13.06 进程管理(三)

--LinuxCPP1306

-13.07 进程间通信(一)

--LinuxCPP1307

-13.08 进程间通信(二)

--LinuxCPP1308

-13.09 进程间通信(三)

--LinuxCPP1309

-13.10 进程间通信(四)

--LinuxCPP1310

-13.11 进程池

--LinuxCPP1311

-13.12 编程实践

--LinuxCPP1312

-第十三讲 进程编程--编程实践提交入口

第十四讲 线程编程

-14.1 提纲

--LinuxCPP1401

-14.2 线程基本概念

--LinuxCPP1402

-14.3 线程管理(一)

--LinuxCPP1403

-14.4 线程管理(二)

--LinuxCPP1404

-14.5 线程管理(三)

--LinuxCPP1405

-14.6 线程管理(四)

--LinuxCPP1406

-14.7 线程同步机制(一)

--LinuxCPP1407

-14.8 线程同步机制(二)

--LinuxCPP1408

-14.9 C++11线程库(一)

--LinuxCPP1409

-14.10 C++11线程库(二)

--LinuxCPP1410

-14.11 C++11线程库(三)

--LinuxCPP1411

-14.12 C++11线程库(四)

--LinuxCPP1412

-14.13 C++11线程库(五)

--LinuxCPP1413

-14.14 编程实践

--LinuxCPP1414

-第十四讲 线程编程--编程实践提交入口

第十五讲 网络编程

-15.1 提纲

--LinuxCPP1501

-15.2 Internet网络协议

--LinuxCPP1502

-15.3 套接字(一)

--LinuxCPP1503

-15.4 套接字(二)

--LinuxCPP1504

-15.5 编程实践

--LinuxCPP1505

-第十五讲 网络编程--编程实践提交入口

课程文档

-课程PDF文件

LinuxCPP0911笔记与讨论

也许你还感兴趣的课程:

© 柠檬大学-慕课导航 课程版权归原始院校所有,
本网站仅通过互联网进行慕课课程索引,不提供在线课程学习和视频,请同学们点击报名到课程提供网站进行学习。