第6章 继承.

Slides:



Advertisements
Similar presentations
第四章 类 和 对 象.
Advertisements

课程 要求 参考 书目 课程 内容 课程 练习.
面向对象的C++程序设计基础 第 4 章 继承与派生.
Oracle数据库 Oracle 子程序.
7.2 访问控制 —— 公有继承 公有继承练习 //Point.h #ifndef _POINT_H #define _POINT_H class Point { //基类Point类的定义 public: //公有函数成员 void initPoint(float x = 0, float.
内容提要 代码重用 类的继承 多态 抽象类 多重继承 虚拟继承. 常宝宝 北京大学计算机科学与技术系
C++面向对象程序设计 第八章 继承和派生.
第四章 继承和派生类 汽车 专用汽车 运输汽车 货车 客车 消防车 洒水车 最普遍、最一般,可以自行驱动 含有汽车的特性,同时与汽车有不同
第14章 c++中的代码重用.
C++ 面对对象程序设计 授课老师:.
第11章 类的继承和派生 继承是面向对象程序设计方法的四个基本特征之一,是程序代码可重用性的具体体现。
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
全国计算机等级考试 二级基础知识 第二章 程序设计基础.
在PHP和MYSQL中实现完美的中文显示
类与对象 Java 实用技术4 类与对象
第10讲 Java面向对象编程基础(4) 教学目标 主要内容.
EBNF 请用扩展的 BNF 描述 C语言里语句的结构; 请用扩展的 BNF 描述 C++语言里类声明的结构;
第11讲 类的继承 1. 类的继承的概念 2. 类的单继承机制 3. 单继承中的构造函数和析构函数.
第12讲 多继承与虚基类 多继承 虚基类.
走进编程 程序的顺序结构(二).
辅导课程六.
绘制圆与多边形 椭圆形 绘制椭圆形的方法是 drawOval(x ,y , width , height), 绘制实心椭圆形的方法是
Zhao4zhong1 (赵中) C语言指针与汇编语言地址.
Zhao4zhong1 (赵中) C语言指针与汇编语言地址.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
Windows网络操作系统管理 ——Windows Server 2008 R2.
第五讲 四则运算计算器(一) 精品教程《C#程序设计与应用(第2版)清华大学出版社 谭恒松 主编
第十章 IDL访问数据库 10.1 数据库与数据库访问 1、数据库 数据库中数据的组织由低到高分为四级:字段、记录、表、数据库四种。
第八章 继承与派生 丘志杰 电子科技大学 计算机学院 软件学院.
第十一章 继承和派生. 主讲教师:全红艳 第十一章 继承和派生.
用event class 从input的root文件中,由DmpDataBuffer::ReadObject读取数据的问题
第七章 操作符重载 胡昊 南京大学计算机系软件所.
SOA – Experiment 2: Query Classification Web Service
C++大学基础教程 第9章 继承与派生 北京科技大学.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
C语言程序设计 主讲教师:陆幼利.
EBNF与操作语义 请用扩展的 BNF 描述 javascript语言里语句的结构;并用操作语义的方法描述对应的语义规则
简单介绍 用C++实现简单的模板数据结构 ArrayList(数组, 类似std::vector)
第11讲 类的继承 1. 类的继承的概念 2. 类的单继承机制 3. 单继承中的构造函数和析构函数.
$9 泛型基础.
C++复习3 ----类的继承与派生.
C#面向对象程序设计 $6 深入理解类.
姚金宇 MIT SCHEME 使用说明 姚金宇
第八讲 面向对象程序设计(一) 精品教程《C#程序设计与应用(第2版)清华大学出版社 谭恒松 主编
分裂对象模型 C++ otcl.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
第4章 Excel电子表格制作软件 4.4 函数(一).
本节内容 类成员的访问控制 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
iSIGHT 基本培训 使用 Excel的栅栏问题
Chapter 18 使用GRASP的对象设计示例.
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
C++语言程序设计 C++语言程序设计 第八章 继承 C++语言程序设计.
辅导课程十五.
Delphi 7.0开发示例.
第7章 模板 陈哲 副教授 南京航空航天大学 计算机科学与技术学院.
本节内容 C语言的汇编表示 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C++语言程序设计 C++语言程序设计 第十一章 异常处理 C++语言程序设计.
Python 环境搭建 基于Anaconda和VSCode.
C++语言程序设计 C++语言程序设计 第八章 继承 C++语言程序设计.
基于列存储的RDF数据管理 朱敏
本节内容 动态链接库 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
第8章 创建与使用图块 将一个或多个单一的实体对象整合为一个对象,这个对象就是图块。图块中的各实体可以具有各自的图层、线性、颜色等特征。在应用时,图块作为一个独立的、完整的对象进行操作,可以根据需要按一定比例和角度将图块插入到需要的位置。 2019/6/30.
第十二讲 继承 与 派生.
WEB程序设计技术 数据库操作.
创建、启动和关闭Activity 本讲大纲: 1、创建Activity 2、配置Activity 3、启动和关闭Activity
使用Fragment 本讲大纲: 1、创建Fragment 2、在Activity中添加Fragment
顺序结构程序设计 ——关于“字符串”和数值.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
Presentation transcript:

第6章 继承

主要内容与学习目标 主要内容: 学习目标: (1)指定派生类与直接基类、private和protected修饰符的含义。 (2)定义派生类的构造函数。 (3)显式调用直接基类实例构造函数。 (4)派生类对象和基类对象的关系、基类变量和派生类变量的关系。 (5)隐藏继承成员、隐藏元素的继承性、使用MyBase访问基类成员。 (6)多级继承、声明可重写方法、重写方法。 (7)基于继承的多态性。 (8)多级继承中构造函数的执行过程、重载/重写和隐藏的比较。 (9)垃圾回收和Finalize方法。 (10)重写Finalize方法。 (11)声明派生类的析构函数。 (12)显式释放资源与实现Dispose方法。 (13)何时使用继承。 学习目标: (1)理解继承和软件重用性。 (2)理解基类与派生类的概念。 (3)掌握访问修饰符public、private和protected的使用。 (4)使用base引用访问基类成员。 (5)如何在基类与派生类中使用构造函数。 (6)理解虚拟方法、重写方法。 (7)理解隐藏继承成员。 (8)了解垃圾回收和Finalize方法。

6.1 直接基类与派生类 任务6.1:定义基类Person 6.1 直接基类与派生类 任务6.1:定义基类Person 问题描述:声明Person类,它有3个属性(身份证号、姓名、性别),一个方法(该方法返回所有属性的值),3个私有字段,一个无参数的实例构造函数和一个有3个参数的实例构造函数。 任务6.2:定义派生类Student(一) 问题描述:声明学生类。 分析:我们要声明学生类(即Student类),由于学生属于人(Person),因此学生具有Person的属性和功能,我们已经有了实现Person的功能和属性的类,要定义学生类,只须以Person类为直接基类定义一派生类,对实现Person的功能和属性的代码不需要重写,直接继承,对于复杂程序, 重复使用已定义好的类,可大大节约程序的开发时间,缩短程序的开发周期。关于如何定义派生类请参考以下程序及说明。 解决方案: (1)打开前面创建的项目InheritsTest,向项目中添加类Student (2)向项目中添加测试类TestInherits (3)添加引用System.Windows.Forms。并将输出类型设置为【Windows应用程序】 (4)按Ctrl+F5键编译并运行应用程序,输出结果如图6.2所示

图6.2 继承基类

6.2 派生类实例构造函数声明 6.2.1 运算符重载 6.2.2 显式调用直接基类实例构造函数 6.2 派生类实例构造函数声明 如果类不包含任何实例构造函数声明,则自动提供一个默认实例构造函数。默认构造函数只是调用直接基类的无参数构造函数。如果直接基类没有可访问的无参数实例构造函数,则发生编译时错误。 如上节程序中,派生类Student不包含任何实例构造函数声明,则自动提供一个默认的无参数实例构造函数调用直接基类的无参数构造函数。如果直接基类有含有参数的实例构造函数声明,则直接基类必须声明无参数实例构造函数,否则发生编译时错误。具体地说,在Person类中,由于含有带参数的实例构造函数声明: public Person(string myid, string myname, string mysex) { ssn = myid; name = name; sex = mysex; } 因此,必须再声明一个无参数构造函数: public Person(){} 否则发生编译时错误。 构造函数是不能继承的,如果派生类需要构造函数,必须声明它。 任务6.3:复数加法 6.2.1 运算符重载 6.2.2 显式调用直接基类实例构造函数

6.2.1 运算符重载 运算符重载可以允许用户定义现有的运算符的新功能, 这样,运算符的一个或两个操作数就可以采用用户定义的类。运算符重载是调用方法的一种方式,要想为类重新定义运算符的功能可采用关键字operator,其一般形式为: public static result-type operator op (object1, object2) { 语句块; } 任务6.4:复数减法 问题描述:声明ComplexNumber类的派生类DComplexNumber,在派生类DComplexNumber中定义一含有参数的实例构造函数。并声明一名称为Subtract的方法,该方法能实现复数减法运算(左操作数的实部减右操作数的实部,左操作数的虚部减右操作数的虚部)。 解决方案: (1)创建DComplexNumber的类。 ①打开前面创建的项目ComplexNumberClass,添加名称为DComplexNumber的类: ②测试以上类。向ComplexNumberClass项目中添加名称为Form1的Windows窗体。 按表6.1向窗体添加控件并设置其属性(参见图6.2)。 (2)在窗体上双击鼠标右键,选择查看代码,打开代码编辑器。 (3)在窗体类Form1中声明如下字段: (4)双击【设置第一个复数】按钮,插入下列代码: (5)双击【设置第二个复数】按钮,插入下列代码: (6)双击“+”按钮,插入下列代码: (7)双击“-”按钮,插入下列代码: (8)按Ctrl+F5键编译并运行应用程序,输出结果如图6.3所示。

表6.1 属性表

图6.3 复数加减法

6.2.2 显式调用直接基类实例构造函数 派生类中至少有一个实例构造函数调用直接基类的实例构造函数。在没有显式指定调用直接基类的实例构造函数时,派生类实例构造函数隐式调用直接基类无参的实例构造函数。如果直接基类没有可访问的无参数实例构造函数,则发生编译时错误。 要在派生类中显式调用直接基类实例构造函数,可通过base关键字指定调用的直接基类构造函数。 在复数减法实例中,DComplexNumber类没有显式调用ComplexNumber的实例构造函数,因此隐式调用ComplexNumber类无参的实例构造函数,如果ComplexNumber类没有可访问的无参数实例构造函数,则发生编译时错误。下面我们修改复数减法实例,在DComplexNumber类中显式地调用ComplexNumber类的实例构造函数。 任务6.5:调用基类实例构造函数

6.3 隐藏从基类继承的成员 可使用new修饰符显式地隐藏从基类继承的成员。若要隐藏继承的成员,请使用相同名称在派生类中声明该成员,并用new修饰符修饰它。若派生类中的成员和基类的成员使用相同的名称、相同的参数和类型等,但未使用new修饰符修饰它,程序编译和运行不会发生错误,但会发出警告。 任务6.6:隐藏继承字段 问题描述:创建一示例程序,在该示例中,基类MyBaseC和派生类MyDerivedC使用相同的字段名 x,从而隐藏了继承字段的值。该示例还说明new修饰符的使用。同时也说明如何使用完全限定名访问基类的隐藏成员。 解决方案: (1)创建一个空项目NewClass,向项目中添加代码文件 (2)添加引用System.Windows.Forms。将输出类型设置为【Windows输出类型】 (3)按Ctrl+F5键编译并运行应用程序,输出结果如图6.4所示

图6.4 隐藏继承字段

6.4 含直接基类构造函数的构造函数声明 派生类继承直接基类中除实例构造函数、静态构造函数外的所有成员,当派生类的字段、属性除了基类的字段、属性外还包括其他字段、属性时,派生类的实例构造函数可以通过指定的参数值调用基类的实例构造函数,初始化基类的字段,然后使用其他参数指定的值初始化派生类特有的字段。 任务6.7:定义派生类Student(二) 问题描述:在任务6.2中,我们声明了一个Student类,Student类除了继承的Person类的属性外,还增加了两个字段studentid、department及属性,因此在声明Student类的实例构造函数时可直接调用基类的实例构造函数,并另外指定私有字段studentid和department的值。 下面我们修改Student类声明,增加实例构造函数声明,并将Print1方法修改为Print方法。 解决方案: (1)打开任务6.2创建的项目InheritsTest。将项目中的Student类修改 (修改处见带底纹部分): (2)按Ctrl+F5键编译并运行应用程序,输出结果如图6.6所示。

图6.6 派生类的实例构造函数 调用基类的实例构造函数 图6.6 派生类的实例构造函数 调用基类的实例构造函数

6.5 虚拟方法与重写方法 任务6.8:多级继承层次结构 6.5.1 继承中构造函数的执行过程 6.5.2 重载、重写和隐藏的比较 6.5 虚拟方法与重写方法 任务6.8:多级继承层次结构 问题描述:声明Point类,它包含Name、X和Y三个属性。不同的形状类,如Rectangle类继承Point,Ellipse类继承Rectangle类,Circle类继承Ellipse,Cylinder类继承Circle类。每个派生类都有各自的Name属性、Area方法(计算图形面积)重写实现。创建每个类的实例,以类的实例作为参数,调用参数的类型为Point或Point数组的ShowShapinfo方法,通过调用重写的方法和属性为相应的图形对象计算表面积、体积并输出图形的名称。 分析:在声明Point类时,由于Point类的派生类必须重写Name属性,因此Point类的Name属性要声明为virtual属性。Rectangle类继承Point,Rectangle类继承了Point的所有的字段、属性,它有自己特有的方法Area(计算矩形面积),但是,我们不希望Rectangle类使用Point类的Name属性,因为一个矩形的名称与点的名称是不同的,Rectangle类应自己来实现其功能,因此,Rectangle类的Name属性必须使用override修饰符,表示它是重写基类的Name属性。由于Rectangle类的派生类必须重写Area方法,因此Rectangle类的Area方法要声明为virtual方法。Ellipse类继承Rectangle类,我们在Ellipse类中定义一个有4个参数的构造函数,这4个参数分别表示椭圆中心的x坐标、y坐标和横轴、纵轴的长度。因此当用“base(...)”调用基类构造函数时,“base(...)”的参数必须访问实例构造函数的参数,以正确地初始化字段的值,也就是说“base(...)”第一个参数的值是椭圆的外接矩形左上角的X坐标,第二个参数的值是椭圆的外接矩形左上角的Y坐标。椭圆中心的x坐标、y坐标与椭圆的外接矩形左上角的X、Y坐标是有关系的,其关系为: X = x - width/2 Y = y - height/2 其中:width、height是椭圆的外接矩形的宽度和高度。 Ellipse类必须重写Area方法和Name属性。Circle类继承Ellipse类,我们在Circle类中定义一有3个参数的构造函数,这3个参数分别表示圆心的X坐标、Y坐标和圆的半径。因此当调用基类构造函数时,必须用实例构造函数初始值设定项访问实例构造函数的参数。Cylinder类从Circle类继承而来,Cylinder类从Circle类继承了方法Area及属性Name。与圆形相比,圆柱体的面积计算方法有所不同,名称也不同,因此Cylinder类必须重写这些方法和属性。图6.7的类图描述了各形状类的继承关系。 6.5.1 继承中构造函数的执行过程 6.5.2 重载、重写和隐藏的比较 6.5.3 垃圾回收和析构函数

图6.7 Point类的继承层次

6.5.1 继承中构造函数的执行过程 每当创建类的实例时,就会调用构造函数。构造函数用于在对象中的任何其他代码执行之前初始化新对象。构造函数可用于打开文件、连接到数据库、初始化变量以及处理任何需要在可使用对象前完成的其他任务。 当创建派生类的实例时,基类的构造函数首先执行,然后执行派生类中的构造函数。这是因为构造函数中方法头后使用语法base(...)。如果没有显示调用基类构造函数,系统隐式调用基类无参的构造函数base()。然后调用该类层次结构中每个类的构造函数,直到到达基类的构造函数。此时,基类构造函数中的代码执行,接着执行所有派生类中每个构造函数的代码,最后执行最相近派生的类中的代码。

6.5.2 重载、重写和隐藏的比较 重载、重写和隐藏是很容易混淆的类似概念。虽然所有这三种技术都使我们得以创建同名的成员,但它们之间有一些重要的差异。 重载的成员用于提供属性或方法的不同版本,这些版本具有相同名称但是接受不同数量的参数或者接受不同数据类型的参数。 重写的属性和方法用于替换在派生类中不适合的继承的属性或方法。重写的成员必须接受同一数据类型和参数数量。派生类继承重写的成员。重写的属性和方法基类中要求有virtual修饰符;派生类中要求有override修饰符。不能扩展被重写的元素的可访问性(例如,无法用public重写protected)。不能更改被重写的属性的可读性或可写性。不能用属性重写方法,或是用方法重写属性。不能用一个void方法重写一个有返回值的方法,反之亦然。重写的元素类型(无返回值方法、有返回值方法或属性)、名称、参数列表和返回类型必须相同。重写的用途主要是为了实现多态性。 隐藏的成员用于局部替换具有更广范围的成员。任何类型都可隐藏任何其他类型。例如,一个int变量可以隐藏一个方法。如果用另外一个方法隐藏某一方法,可以使用一个不同的参数列表以及一个不同的返回类型。若隐藏元素在后来的派生类中不可访问,则没有继承隐藏。例如,如果声明隐藏元素为private,则派生类的继承类就会继承原始元素,而不是隐藏元素。隐藏的用途主要是为了防止后面的基类修改引入已在派生类中声明的成员。它不能实现多态性,例如,如果Ellipse类的Area方法隐藏基类Rectangle类的Area方法,当把Ellipse类的对象传递给需要Rectangle对象的ShowArea方法时,则执行Rectangle对象的Area方法,而不会执行Ellipse对象的Area方法。 修改“实例:多级继承层次结构”,将Ellipse、Circle、Cylinder类中的Area方法的overrides修饰符改为new修饰符,则程序运行结果如图6.9所示。

图6.9 隐藏不能实现多态性

6.5.3 垃圾回收和析构函数 分配并且确保进行对应的释放会非常费时,而且可能会很难。.NET Framework使用名为“引用跟踪垃圾回收”的系统,该系统定期释放未使用的资源。当系统确定对象不再需要时,公共语言运行库(CLR)便定期销毁这些对象。当系统资源短缺时,对象释放会快一些,否则就不那么频繁。至于何时销毁不再需要的对象,进行垃圾回收释放未使用的资源,是不确定的。在此类情况下,称对象具有“非确定性生存期”。在大多数情况下,非确定性生存期并不会对如何编写应用程序产生影响,只要记住销毁对象的动作可能不会在对象丧失范围时立即执行即可。 垃圾回收有一个缺点:在你创建封装非托管资源的对象时,当你在应用程序中使用完这些非托管资源之后,你必须显式地释放它们。最常见的一类非托管资源就是包装操作系统资源的对象,例如文件、窗口或网络连接。虽然垃圾回收器可以跟踪封装非托管资源的对象的生存期,但它不了解具体如何清理这些资源。对于这些类型的对象,C#提供析构函数,它允许对象在垃圾回收器回收该对象使用的内存时适当清理其非托管资源。 1. 析构函数 任务6.9:保存状态信息 2. 声明派生类的析构函数 任务6.10:保存雇员状态信息