第九章 继承.ppt_第1页
第九章 继承.ppt_第2页
第九章 继承.ppt_第3页
第九章 继承.ppt_第4页
第九章 继承.ppt_第5页
已阅读5页,还剩12页未读 继续免费阅读

下载本文档

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

文档简介

1、第九章继承1.继承的概念,继承是c+语言的一种重要机制,该机制自动地为一个类提供来自另一个类的操作和数据结构,这使得程序员只需在新类中定义已有类中没有的成分来建立新类。面向对象的程序设计方式可以很方便的声明一个新类作为另一个类的派生。派生类(子类)继承它父类的属性和操作。子类也声明了新的属性和新的操作,剔除了那些不适合于其用途的继承下来的操作。这样,通过继承可以重用父类的代码,从而专注于为子类编写新代码。那些父类已经存在,在新的应用中,无须修改父类。所要做的就是派生子类,在子类中做一些增加和修改。这种机制,使重用成为可能。,2.继承的工作方式,现有一个学生类Student,要增加研究生类Gra

2、duateStudent。由于研究生除了他自己特有的性质外,具有学生的所有性质,所以我们用继承的方法来重用学生类。classStudent/;classGraduateStudent:publicStudent/;在这里,一个GraduateStudent类继承了Student类的所有成员。继承的方式是在类定义中类名后跟“:publicStudent”。一个研究生是一个学生。当然,GraduateStudent也包含有自己特有的成员。,对于下面的代码:voidfn(Student函数fn()期望接受Student类对象作为它的参数,来自main()的调用传给它一个GraduateStudent

3、对象,fn()把它视同Student对象予以接受。事实上,GraduateStudent的内存布局,也与“gs是研究生,当然也是学生”相吻合,gs对象的最初部分是Student数据成员。Fn(gs)等于做了一个Student(gs)的隐式转换,指向gs的this指针也就是指向Student对象的指针。,3.派生类的构造,派生类在创建时,将执行其默认的构造函数,该默认构造函数首先会调用基类的默认构造函数。派生类可以直接访问基类的保护数据成员,甚至在构造时初始化它们,但一般不这么做,而是通过基类的接口(成员函数)去访问它们,初始化也是通过基类的构造函数。这样一旦基类的实现有错误,只要不涉及接口,那

4、么基类的修改不会影响派生类的操作。派生类的析构函数以构造函数相反的顺序被调用。,例如:classGraduateStudent:publicStudentpublic:GraduateStudent(char*pName,Advisor基类初始化由Student(pName)去完成,派生类的构造总是由基类的初始化开始的。advisor是GraduateStudent的数据成员,它是Adivisor类对象。advisor(adv)表示以adv的值来初始化advisor,将调用Advisor的默认拷贝构造函数。,4.继承与组合,类以另一个类对象作数据成员,称为组合。例如:classVehicle/

5、;classMotor/;classCar:publicVehiclepublic:Motormotor;voidvehicleFn(Vehicle/ok,5.多态性,C+允许子类的成员函数重载基类的成员函数。例如:classStudentpublic:/floatcalcTuition()/计算学费;classGraduateStudent:publicStudentpublic:/floatcalcTuition()/;voidmain()Students;GraduateStudentgs;s.calcTuition();/调用Student:calcTuition()gs.calcTu

6、ition();/调用GraduateStudent:calcTuition(),有时候,会碰到对象所属的类不能确定的情况,例如:classStudentpublic:/floatcalcTuition()/计算学费;classGraduateStudent:publicStudentpublic:/floatclacTuition()/;voidfn(Student/计算一下研究生gs的学费函数调用的实际参数,随应用程序的运行进展而变更,要求函数fn()的行为也要随着变更。这样,函数fn()的运行执行代码就无法在编译时被确定。C+的继承机制中用多态性(或称迟后联编latebinding)来解

7、决这一问题,在运行时,能根据其类型确定调用哪个函数。,如果不支持多态性,那么不得不人为增加一段代码,例如:enumStudentType(STUDENT,GRADUATESTUDENT);classStudentpublic:Student(char*pName=“noname”type=STUDENT;/floatcalcTuition();StudentTypetype;/说明为公共的,便于应用程序访问/;classGraduateStudent:publicStudentpublic:GraduateStudent()type=GRADUATESTUDENT;floatcalcTuiti

8、on();/;voidfn(Student/如果又继承新的类,应用程序的维护量很大,失去了面向对象的优越性。,为了指明某个成员函数具有多态性,用关键字virtual来标志其为虚函数。编译通常是在先期联编(earlybinding)状态下工作的,只有看见虚函数,才把它作为迟后联编来实现。多态性增加了一些数据存储和执行指令的代价,但与所得到的编程灵活性和方便性相比,还是值得的。基类中声明为virtual的虚函数的性质自动地向下带给其子类,所以子类中的virtual可以省略。,6.虚函数,如果虚函数在基类与子类中出现的仅仅是名字的相同,而参数类型不同,或返回类型不同,即使写上了virtual关键字,

9、则也不进行迟后联编。一个类中将所有的成员函数都尽可能地设置为虚函数总是有益的,设置时需要注意:1)只有类的成员函数才能说明为虚函数;2)静态成员函数不能是虚函数,因为静态成员函数不受限于某个对象;3)内联函数不能是虚函数,因为内联函数是不能在运行中动态确定其位置的。即使虚函数在类的内部定义,编译时,仍将其看作非内联的;4)构造函数不能是虚函数,因为构造时,对象还是一片未定型的空间;5)析构函数可以是虚函数,而且通常是虚函数,例如当基类对象和子类对象以不同方式申请了堆空间后:voidfinishWithObject(Base*pHeapObject)/deletepHeapObject;在执行d

10、eletepHeapObject时,要调用析构函数,但是执行基类还是子类的析构函数,需要虚函数来解决。,7.类的冗余,继承给程序员可在一个过程中从不同类里组合共有特征的能力,这个过程称为分解(factoring)。也就是把共同的特征分解到基类中。类的层次关系必须其意义,否则会使程序员混淆。从相似的类中,将共有特征提取出来的过程称为分解,分解使类的层次合理化和减少冗余。只有当继承关系与实际相符合时,分解才是合理的。,8.抽象类,C+允许程序员声明一个不能有实例对象的类,这样的类唯一的用途就是被继承,这种类被称为抽象类。一个抽象类至少具有一个纯虚函数。所谓纯虚函数是指被标明为不具体实现的虚成员函数

11、。例如:virtualvoidWithdrawal(floatamount)=0;在Withdrawal()之后声明的“=0”表明程序员将不定义该函数。该声明是为派生类而保留的位置。派生类将用一个具体的函数来重载该函数。一个抽象类不能有实例对象,即不能由该类抽象来制造一个对象。所以,下面的声明是非法的:voidfunc()Accounta(3145,300.0);a.Withdrawal(100);抽象类是作为基类为其他类服务的。,直到所有纯虚函数被重载之前,抽象类的子类也一直都保持抽象状态。例如:classDisplay/显示器类public:virtualvoidinit()=0;/纯虚函

12、数virtualvoidwrite(char*pString)=0;classMonochrome:publicDisplay/单色显示器类virtualvoidinit();virtualvoidwrite(char*pString);classColorAdapter:publicDisplay/彩色显示器类virtualvoidwrite(char*pString);classSVGA:publicColorAdapter/VGA系列彩色显示器类virtualvoidinit();voidMonochrome:init()/省略voidMonochrome:write(char*pStr

13、ing)/省略voidColorAdapter:write(char*pString)/省略voidSVAG:init()/省略voidfunc()Monochromemc;SVGAsvga;,9.纯虚函数的必要性,不能创建一个抽象类的对象,但是可以声明一个抽象类的指针和引用。例如:voidfunc(Account*pA)/专门处理帐户中的取款pA-Withdrawal(100.0);voidotherFunc()Savingss;Checkingc;func(/合法:一个Checking也是一个Account从otherFunc()函数调用func()时,传递的实参是具有实际地址的子类对象,

14、但决不可能是Account类对象。,如果在Account类里去掉Withdrawal()纯虚函数,使得在其子类中分别添加Withdrawal()成员函数的定义,程序仍能通过编译和连接,在某些情况下也能运行。但若考虑上例多态的情形,则下例的代码不能通过编译:classAccount/除了不声明Withdrawal()外,其他都一样;classSavings:publicAccountpublic:virtualvoidWithdrawal(floatamount);voidfunc(Account*pA)pA-Withdrawal(100.0);/error:Withdrawal()不是Account成员voidmain()Savingss;func(纯虚函数是在基类中为子类保留的一个位置,以便子类用自己的实在函数定义来重载它。如果在基类中没有保留位置,则就没有重载。,10.多重继承,我们可以为一个派生类指定多个基类,这样的继承结构被称为多重继承。当一个类是两个或多个基类的派生类是,必须在派生类名和冒号之后,列出所有基类的类名,基类间用逗号各开。

温馨提示

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

评论

0/150

提交评论