第八章_继承与多态(C++程序设计(第2版)吴乃陵).ppt_第1页
第八章_继承与多态(C++程序设计(第2版)吴乃陵).ppt_第2页
第八章_继承与多态(C++程序设计(第2版)吴乃陵).ppt_第3页
第八章_继承与多态(C++程序设计(第2版)吴乃陵).ppt_第4页
第八章_继承与多态(C++程序设计(第2版)吴乃陵).ppt_第5页
已阅读5页,还剩28页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

继承 inheritance 继承机制是面向对象程序设计使代码可以复用的最重要的手段 它允许程序员在保持原有类特性的基础上进行扩展 增加功能 这样产生新的类 称派生类 继承呈现了面向对象程序设计的层次结构 体现了由简单到复杂的认识过程 多态性 polymorphism 多态性是考虑在不同层次的类中 以及在同一类中 同名的成员函数之间的关系问题 函数的重载 运算符的重载 属于编译时的多态性 以虚函数为基础的运行时的多态性是面向对象程序设计的标志性特征 体现了类推和比喻的思想方法 第八章继承与多态 第八章继承与多态 8 1继承与派生的概念 8 4虚基类 选读 8 3多重继承与派生类成员标识 8 6多态性与虚函数 8 5派生类应用讨论 8 2派生类的构造函数与析构函数 8 1继承与派生的概念 层次概念是计算机的重要概念 通过继承 inheritance 的机制可对类 class 分层 提供类型 子类型的关系 C 通过类派生 classderivation 的机制来支持继承 被继承的类称为基类 baseclass 或超类 superclass 新的类为派生类 derivedclass 或子类 subclass 基类和派生类的集合称作类继承层次结构 hierarchy 层次概念 派生反映了事物之间的联系 事物的共性与个性之间的关系 派生与独立设计若干相关的类 前者工作量少 重复的部分可以从基类继承来 不需要单独编程 8 1继承与派生的概念 8 1 1类的派生与继承 8 1 2公有派生与私有派生 派生类的定义 class派生类名 访问限定符基类名1 访问限定符基类名2 访问限定符基类名n private 成员表1 派生类增加或替代的私有成员 public 成员表2 派生类增加或替代的公有成员 protected 成员表3 派生类增加或替代的保护成员 分号不可少其中基类1 基类2 是已声明的类 在派生类定义的类体中给出的成员称为派生类成员 它们是新增加成员 它们给派生类添加了不同于基类的新的属性和功能 派生类成员也包括取代基类成员的更新成员 8 1 1类的派生与继承 a 多重继承 b 单继承 图8 1多重继承与单继承 一个基类可以直接派生出多个派生类 派生类可以由多个基类共同派生出来 称多重继承 8 1 1类的派生与继承 多重继承 如果一个派生类可以同时有多个基类 称为多重继承 multiple inheritance 这时的派生类同时得到了多个已有类的特征 单继承 派生类只有一个直接基类的情况称为单继承 single inheritance 8 1 1类的派生与继承 在派生过程中 派生出来的新类同样可以作为基类再继续派生出更新的类 依此类推形成一个层次结构 直接参与派生出某类称为直接基类 而基类的基类 以及更深层的基类称为间接基类 类族 同时一个基类可以直接派生出多个派生类 这样形成了一个相互关联的类族 如MFC就是这样的族类 它由一个CObject类派生出200个MFC类中的绝大多数 多层次继承 编制派生类时可分四步 吸收基类的成员 改造基类成员 发展新成员 重写构造函数与析构函数 8 1 1类的派生与继承 不论是数据成员 还是函数成员 除构造函数与析构函数外全盘接收 声明一个和某基类成员同名的新成员 派生类中的新成员就屏蔽了基类同名成员称为同名覆盖 override 派生类新成员必须与基类成员不同名 它的加入保证派生类在功能上有所发展 派生编程步骤 8 1 1类的派生与继承 第二步中 新成员如是成员函数 参数表也必须一样 否则是重载 第三步中 独有的新成员才是继承与派生的核心特征 第四步是重写构造函数与析构函数 派生类不继承这两种函数 不管原来的函数是否可用一律重写可免出错 例题 基类与派生类的定义和实现 访问控制 亦称为继承方式 是对基类成员进一步的限制 访问控制也是三种 公有 public 方式 亦称公有继承保护 protected 方式 亦称保护继承私有 private 方式 亦称私有继承 8 1 2公有派生与私有派生 访问限定符两方面含义 派生类成员 新增成员 函数对基类 继承来的 成员的访问 调用和操作 和从派生类对象之外对派生类对象中的基类成员的访问 即内部访问和对象访问 1 公有继承当类的继承方式为公有继承时 基类的public成员和protected成员被继承到派生类中仍作为派生类的public成员和protected成员 派生类的其他成员可以直接访问它们 但是 类的外部使用者只能通过派生类的对象访问继承来的public成员 基类的private成员在私有派生类中是不可直接访问的 所以无论是派生类成员还是通过派生类的对象 都无法直接访问从基类继承来的private成员 但是可以通过基类提供的public成员函数间接访问它们 8 1 2公有派生与私有派生 访问限定符两方面含义 派生类成员 新增成员 函数对基类 继承来的 成员的访问 调用和操作 和从派生类对象之外对派生类对象中的基类成员的访问 即内部访问和对象访问 2 保护继承当类的继承方式为保护继承时 基类的public成员和protected成员被继承到派生类中都作为派生类的protected成员 派生类的其他成员可以直接访问它们 但是类的外部使用者不能通过派生类的对象来访问它们 基类的private成员在私有派生类中是不可直接访问的 所以无论是派生类成员还是通过派生类的对象 都无法直接访问基类的private成员 8 1 2公有派生与私有派生 访问限定符两方面含义 派生类成员 新增成员 函数对基类 继承来的 成员的访问 调用和操作 和从派生类对象之外对派生类对象中的基类成员的访问 即内部访问和对象访问 3 私有继承当类的继承方式为私有继承时 基类的public成员和protected成员被继承后作为派生类的private成员 派生类的其他成员可以直接访问它们 但是在类外部通过派生类的对象无法访问 基类的private成员在私有派生类中是不可直接访问的 所以无论是派生类成员还是通过派生类的对象 都无法直接访问从基类继承来的private成员 但是可以通过基类提供的public成员函数间接访问 派生类构造函数和析构函数的执行顺序通常情况下 当创建派生类对象时 首先执行基类的构造函数 随后再执行派生类的构造函数 当撤消派生类对象时 则先执行派生类的析构函数 随后再执行基类的析构函数 8 2派生类的构造函数与析构函数 例基类和派生类的构造函数及析构函数的执行顺序 includeclassBase public Base cout Constructingbaseclass n 基类的构造函数 Base cout Destructingbaesclass n 基类的析构函数 classDerive publicBase public Derive cout Constructingderivedclass n 派生类的构造函数 Derive cout Destructingderivedclass n 派生类的析构函数 main Deriveop return0 派生类构造函数的定义 派生类名 派生类名 参数总表 基类名1 参数名表1 基类名2 参数名表2 基类名n 参数名表n 成员对象名1 成员对象参数名表1 成员对象名m 成员对象参数名表m 派生类新增成员的初始化 所列出的成员对象名全部为新增成员对象的名字 注意 在构造函数的声明中 冒号及冒号以后部分必须略去 所谓不能继承并不是不能利用 而是把基类的构造函数作为新的构造函数的一部分 或者讲调用基类的构造函数 基类名仅指直接基类 写了底层基类 编译器认为出错 冒号后的基类名 成员对象名的次序可以随意 这里的次序与调用次序无关 8 2派生类的构造函数与析构函数 派生类构造函数各部分执行次序 1 调用基类构造函数 按它们在派生类定义的先后顺序 顺序调用 2 调用成员对象的构造函数 按它们在类定义中声明的先后顺序 顺序调用 3 派生类的构造函数体中的操作 8 2派生类的构造函数与析构函数 注意 在派生类构造函数中 只要基类不是使用缺省构造函数都要显式给出基类名和参数表 如果基类没有定义构造函数 则派生类也可以不定义 全部采用系统给定的缺省构造函数 如果基类定义了带有形参表的构造函数时 派生类就应当定义构造函数 8 2派生类的构造函数与析构函数 析构函数 析构函数的功能是作善后工作 只要在函数体内把派生类新增一般成员处理好就可以了 而对新增的成员对象和基类的善后工作 系统会自己调用成员对象和基类的析构函数来完成 析构函数各部分执行次序与构造函数相反 首先对派生类新增一般成员析构 然后对新增对象成员析构 最后对基类成员析构 例8 1 由在册人员类公有派生学生类 我们希望基类和派生类共享相同的公有接口 只能采用公有派生来实现 基类 classPerson stringIdPerson 身份证号 18位数字stringName 姓名TsexSex 性别enumTsex mid man woman intBirthday 生日 格式1986年8月18日写作19860818stringHomeAddress 家庭地址 public Person string string Tsex int string 构造函数Person 缺省的构造函数 Person 析构函数 voidSetName string 修改名字stringGetName returnName 提取名字voidSetSex Tsexsex Sex sex 修改性别TsexGetSex returnSex 提取性别voidSetId stringid IdPerson id 修改身份证号stringGetId returnIdPerson 提取身份证号voidSetBirth intbirthday Birthday birthday 修改生日intGetBirth returnBirthday 提取生日voidSetHomeAdd string 修改住址stringGetHomeAdd returnHomeAddress 提取住址voidPrintPersonInfo 输出个人信息 接口函数 派生的学生类 classStudent publicPerson 定义派生的学生类stringNoStudent 学号coursecs 30 30门课程与成绩public Student stringid stringname Tsexsex intbirthday stringhomeadd stringnostud 注意派生类构造函数声明方式Student 缺省派生类构造函数 Student 派生类析构函数SetCourse string int 课程设置intGetCourse string 查找成绩voidPrintStudentInfo 打印学生情况 structcourse stringcoursename intgrade 在VC 平台上运行例8 1 验证主函数 一 派生类与基类 在任何需要基类对象的地方都可以用公有派生类的对象来代替 这条规则称赋值兼容规则 它包括以下情况 8 5派生类应用讨论 1 派生类的对象可以赋值给基类的对象 这时是把派生类对象中从对应基类中继承来的成员赋值给基类对象 反过来不行 因为派生类的新成员无值可赋 2 可以将一个派生类的对象的地址赋给其基类的指针变量 但只能通过这个指针访问派生类中由基类继承来的成员 不能访问派生类中的新成员 同样也不能反过来做 3 派生类对象可以初始化基类的引用 引用是别名 但这个别名只能包含派生类对象中的由基类继承来的成员 例8 5 为例8 1定义拷贝函数和运算符 重载函数 二 继承与聚合继承使派生类可以利用基类的成员 如果我们把基类的对象作为一个新类的对象成员 也可以取得类似的效果 派生类采用继承方法 成员对象是聚合的概念 基类在派生类中只能继承一个 间接基类不在讨论之中 不能同时安排两个 否则成员名即使使用域分辨符也会发生冲突 classA public intK classB publicA publicA 两个A无论如何无法分辨出来 如果要用两个A只能采用成员对象 更深入地探讨后会发现 成员对象体现了封装更深层次的含义 在派生类和它的基类中是不应该有内存的动态分配的 动态分配的部分应该封装在成员对象中 在该成员对象的析构函数中释放内存 在该成员对象中提供深拷贝 类string就是如此 它的内部就是一个完备的小系统 这样程序员就可以放心地使用它 而不需要为它做任何事情 8 5派生类应用讨论 三 派生类与模板 为了运行的效率 类模板是相互独立的 即独立设计 没有使用继承的思想 对类模板的扩展是采用适配子 adapter 来完成的 通用性是模板库的设计出发点之一 这是由泛型算法和函数对象等手段达到的 派生类的目标之一也是代码的复用和程序的通用性 最典型的就是MFC 派生类的优点是可以由简到繁 逐步深入 程序编制过程中可以充分利用前面的工作 一步步完成一个复杂的任务 模板追求的是运行效率 而派生追求的是编程的效率 8 5派生类应用讨论 8 6多态性与虚函数 多态性 多态性是面向对象程序设计的关键技术之一 若程序设计语言不支持多态性 不能称为面向对象的语言 利用多态性技术 可以调用同一个函数名的函数 实现完全不同的功能 在C 中有两种多态性 编译时的多态性 运行时的多态性 运行时的多态性是指在程序执行前 无法根据函数名和参数来确定该调用哪一个函数 必须在程序执行过程中 根据执行的具体情况来动态地确定 它是通过类继承关系和虚函数来实现的 目的也是建立一种通用的程序 通用性是程序追求的主要目标之一 通过函数的重载和运算符的重载来实现的 8 6多态性与虚函数 8 6 1虚函数的定义 8 6 4动态绑定 选读 8 6 2纯虚函数 8 6 3继承与多态的应用 单链表派生类 选读 8 6 1虚函数的定义 虚函数的概念 虚函数是一个类的成员函数 定义格式如下 virtual返回类型函数名 参数表 关键字virtual指明该成员函数为虚函数 virtual仅用于类定义中 如虚函数在类外定义 不可再加virtual 当一个类的某个成员函数被定义为虚函数 则由该类派生出来的所有派生类中 该函数始终保持虚函数的特征 8 6 1虚函数的定义 当在派生类中重新定义虚函数 overridingavirtualfunction 亦译作超载或覆盖 时 不必加关键字virtual 但重新定义时不仅要同名 而且它的参数表和返回类型全部与基类中的虚函数一样 否则出错 虚函数与在8 1 1节中介绍的派生类的第二步 改造类成员 同名覆盖 override 有关 如未加关键字virtual 则是普通的派生类中的新成员函数覆盖基类同名成员函数 当然参数表必须一样 否则是重载 可称为同名覆盖函数 它不能实现运行时的多态性 虚函数定义要点 虚函数与运行时的多态性 例8 6 计算学分 可由本科生类派生出研究生类 但它们各自的从课程学时数折算为学分数的算法是不同的 本科生是16个学时一学分 而研究生是20个学时一学分 8 6 1虚函数的定义 例8 7 计算学分 派生类定义不再重复 成员函数设置为虚函数的要点 1 派生类中定义虚函数必须与基类中的虚函数同名外 还必须同参数表 同返回类型 否则被认为是重载 而不是虚函数 2 只有类的成员函数才能说明为虚函数 这是因为虚函数仅适用于有继承关系的类对象 3 静态成员函数 是所有同一类对象共有 不受限于某个对象 不能作为虚函数 4 一个类对象的静态和动态类型是相同的 实现动态多态性时 必须使用基类类型的指针变量或引用 使该指针指向该基类的不同派生类的对象 并通过该指针指向虚函数 才能实现动态的多态性 8 6 1虚函数的定义 5 内联函数每个对象一个拷贝 无映射关系 不

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论