《皮德常C++程序设计教程》Chapter-10_第1页
《皮德常C++程序设计教程》Chapter-10_第2页
《皮德常C++程序设计教程》Chapter-10_第3页
《皮德常C++程序设计教程》Chapter-10_第4页
《皮德常C++程序设计教程》Chapter-10_第5页
已阅读5页,还剩53页未读 继续免费阅读

下载本文档

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

文档简介

第10章继承、多态和虚函数皮德常南京航空航天大学计算机科学与技术学院110.1继承继承是OOP程序设计中很重要的一个方面。继承易于扩充现有类以满足新的应用。将已有的类称之为父类,也称基类,将新产生的类称为子类,也称为导出类或派生类。导出类不做任何改变地继承了基类中的所有变量和函数〔构造函数和析构函数除外〕,并且还可以增加新的数据成员和函数,从而使导出类比基类更为特殊化。Example:例10-1.2//Contentsofgrade.hclassGrade{ charletter; floatscore; voidcalcGrade();public: voidsetScore(floats){score=s;calcGrade();} floatgetScore(){returnscore;} chargetLetter(){returnletter;}};3//Contentsofgrade.cpp

#include"grade.h"//DefinitionofmemberfunctionGrade::calcGradevoidGrade::calcGrade(){ if(score>89) letter='A'; elseif(score>79)letter='B'; elseif(score>69)letter='C'; elseif(score>59)letter='D'; elseletter='F';}4//Contentsoftest.h#include"grade.h"classTest:

publicGrade{ int numQuestions; float pointsEach; int numMissed;public: Test(int,int);};5//Contentsoftest.cpp#include"test.h"//参数q代表问题的个数,m代表答错的题数.Test::Test(intq,intm){ floatnumericGrade; numQuestions=q; numMissed=m; pointsEach=100.0f/numQuestions; numericGrade=100.0f-numMissed*pointsEach;

setScore(numericGrade);}6#include"test.h"voidmain(){ intquestions,missed; cout<<"Howmanyquestions?"; cin>>questions; cout<<"Howmanyquestionsmissed?"; cin>>missed; Testexam(questions,missed); cout.precision(2); cout<<"\nThescoreis"<<exam.getScore(); cout<<"\nThegradeis"<<exam.getLetter();}grade.hgrade.cpptest.htest.cpp10-1.cpp7上例中,父类中的公有成员在子类中仍是公有的,它们可以和子类中的公有成员一样被访问。但反过来是错误的,基类对象或基类中的某个函数不能调用子类中的函数。classBadBase{ intx;public: BadBase(){x=getVal();}//Error};classDerived:publicBadBase{ inty;public: Derived(intz){y=z;} intgetVal(){returny;}};810.2保护成员和类的访问基类中的保护成员和私有成员比较类似,唯一的区别是:子类不可访问基类中的私有成员,但可访问基类中的保护成员。在公有继承或保护继承的情况下,子类能访问基类的protected成员。Example:例10-29//Contentsofgrade2.hclassGrade{protected:

charletter; floatscore; voidcalcGrade();public: voidsetScore(floats){score=s;calcGrade();} floatgetScore(){returnscore;} chargetLetter(){returnletter;}};10//Contentsoftest2.h#include"grade2.h"classTest:publicGrade{ int numQuestions; float pointsEach; int numMissed;public: Test(int,int);

voidadjustScore();//新增加的函数};11//Contentsoftest2.cpp#include"test2.h"//构造函数略voidTest::adjustScore(){ if((score-int(score))>=0.5f){ score+=0.5; calcGrade(); }}who12继承方式基类成员在子类中的表现private1.基类的私有成员在子类中不可访问;2.基类的保护成员变成了子类中的私有成员;3.基类的公有成员变成了子类中的私有成员。protected1.基类的私有成员在子类中不可访问;2.基类的保护成员变成了子类中的保护成员;3.基类的公有成员变成了子类中的保护成员。public1.基类的私有成员在子类中不可访问;2.基类的保护成员变成了子类中的保护成员;3.基类的公有成员变成了子类中的公有成员。13private:xprotected:ypublic:zprivate:xprotected:ypublic:zprivate:xprotected:ypublic:zxisinaccessibleprivate:yprivate:zxisinaccessibleprotected:yprotected:zxisinaccessibleprotected:ypublic:zprivatebaseclassprotectedbaseclasspublicbaseclassExample:14注意如果省略了继承修饰符,那么就是私有继承: classTest:Grade不要将继承修饰符与成员的访问修饰符相混淆:成员访问修饰符是规定类外语句能否访问类中的成员,而继承修饰符是为了限定基类成员在子类中的表现。1510.3构造函数和析构函数当基类和子类都有构造函数时,如果定义一个子类对象,那么首先要调用基类的构造函数,然后再调用子类的构造函数;析构函数的调用次序与此相反,即先调用子类的析构函数,然后再调用基类的析构函数。Example:

例10-3.16classBaseDemo{public: BaseDemo() {cout<<"InBaseDemoconstructor.\n";} ~BaseDemo() {cout<<"InBaseDemodestructor.\n";}};classDerivedDemo:publicBaseDemo{public: DerivedDemo() {cout<<"InDerivedDemoconstructor.\n";} ~DerivedDemo() {cout<<"InDerivedDemodestructor.\n";}};17voidmain(){ cout<<"下面定义一个DerivedDemo类对象\n"; DerivedDemoobject;

cout<<"下面将要结束程序

\n";}10-3.cpp1810.3.2向基类的构造函数传参数如果基类和子类都有缺省的构造函数,它们的调用是自动完成的,这是一种隐式调用。如果基类的构造函数带有参数,那么必须让子类的构造函数显式调用基类的构造函数,并且向基类构造函数传递适当的参数。例10-419classRectangle{protected: floatwidth,length,area;public: Rectangle(){width=length=area=0.0f;}

Rectangle(floatw,floatl)

{ width=w;length=l; area=width*length; } floatgetArea(){returnarea;} floatgetLen(){returnlength;} floatgetWidth(){returnwidth;}};20classCube:publicRectangle{protected: floatheight,volume;public:

Cube(float,float,float); floatgetHeight(){returnheight;} floatgetVol(){returnvolume;}};Cube::Cube(floatw,floatl,floath):Rectangle(w,l){ height=h;volume=area*height;}Rectangle.hRectangle.cppCube.hCube.cpp10-4.cpp21Note如果基类没有缺省的构造函数,那么子类必须至少具有一个带参的构造函数,以便向基类构造函数传递参数。2210.3.3初始化列表的作用1.

如果类之间具有继承关系,子类必须在其初始化列表中调用基类的构造函数。例:classBase{ Base(intx);}; classDerived:publicBase{ Derived(intx,inty):Base(x)

{ /*…*/} };2310.3.3初始化列表的作用2.

类中的const常量只能在初始化列表中进行初始化,而不能在函数体内用赋值的方式来初始化。classBase{

constintSIZE;

Base(intsize):SIZE(size)

{/*…*/}};Baseone(100);2410.3.3初始化列表的作用3.对象类型的成员的初始化放在初始化列表中,那么效率较高,反之较低。根本类型变量的初始化可以在初始化列表中,也可在构造函数中,效率上没区别。classBase{Base();Base(constBase&other);};classDerived{BaseB_Member;public:Derived(constBase&a);};构造函数的实现:Derived::Derived(constBase&b):B_Member(b){/*…*/}也可这样实现,但效率较低。Derived::Derived(constBase&b){B_Member=b;}2510.4覆盖基类的函数成员重载的特点:(1)重载表现为有多个函数,它们的名字相同,但参数不全相同;(2)重载可以出现在同一个类中,也可出现在具有继承关系的父类与子类中;(3)重载也可表现为外部函数的形式。2610.4覆盖基类的函数成员覆盖的特点:(1)覆盖一定出现在具有继承关系的基类和子类之间;(2)覆盖除了要求函数名完全相同,还要求相应的参数个数和类型也完全相同;(3)当进行函数调用时,子类对象所调用的是子类中定义的函数;(4)覆盖是C++多态性的局部表达。27classMileDist{protected:floatmiles;public: voidsetDist(floatd){miles=d;} floatgetDist(){returnmiles;}};classFeetDist:publicMileDist{ protected:floatfeet;public: voidsetDist(float); floatgetDist(){returnfeet;} floatgetMiles(){returnmiles;}};28voidFeetDist::setDist(floatft){ feet=ft;

MileDist::setDist(feet/5280);//Callbaseclassfunction}voidmain(){FeetDistfeet;floatft;cout<<"Adistanceinfeetandconvertittomiles:";cin>>ft;feet.setDist(ft);cout<<feet.getDist()<<"feetequals";cout<<feet.getMiles()<<"miles.\n";}哪一个?MileDist.hFeetDist.hFeetDist.cpp10-5.cpp2910.5虚函数函数覆盖表达了一定的多态性。但是,简单的函数覆盖并不能称为真正的多态性。Example:例10-730classMileDist{protected: floatmiles;public: voidsetDist(floatd){miles=d;} floatgetDist(){returnmiles;} floatsquare(){returngetDist()*getDist();}};who31classFeetDist:publicMileDist{protected: floatfeet;public: voidsetDist(float); floatgetDist(){returnfeet;} floatgetMiles(){returnmiles;}};voidFeetDist::setDist(floatft){ feet=ft; MileDist::setDist(feet/5280);}32voidmain(){ FeetDistfeet; floatft; cout<<"请输入以英尺为单位的距离:"; cin>>ft; feet.setDist(ft); cout<<feet.getDist()<<"英尺等于"; cout<<feet.getMiles()<<"英里\n"; cout<<feet.getDist()<<"平方等于"; cout<<feet.square()<<"\n";}MileDist2.hFeetDist2.hFeetDist2.cpp10-7.cpp33错误的原因:C++编译器在缺省情况下,对函数成员的调用实施的是静态连编〔也称静态绑定〕。解决方法:将getDist设置为虚函数。对于虚函数,编译器完成的是动态连编〔也称动态绑定〕,即对函数的调用是在运行时确定的。OOP:覆盖和重载不能表达真正的多态性,只有虚函数才是多态性的表现。不支持多态性的语言,就不能称为OOP。3410.6纯虚函数和抽象类纯虚函数是在基类中声明的虚函数,没有函数体,要求继承基类的子类必须覆盖它。带有纯虚函数的类称为抽象类,不能定义抽象类的对象。派生类可以根据自己的需要,分别覆盖它,从而实现真正意义上的多态性。格式:virtualvoidshowInfo()=0;35classStudent//例10-9{protected: charname[51]; inthours;public: Student(){name[0]=hours=0; } voidsetName(char*n){strcpy(name,n);} //Purevirtualfunction

virtualvoidsetHours()=0; virtualvoidshowInfo()=0;};36classCsStudent:publicStudent{ intmathHours,csHours;public: voidsetMathHours(intmh){mathHours=mh;} voidsetCsHours(intcsh){csHours=csh;} voidsetHours() { hours=mathHours+csHours; } voidshowInfo();};37voidCsStudent::showInfo(){ cout<<"Name:"<<name<<endl; cout<<"\tMath:"<<mathHours<<endl; cout<<"\tCS:"<<csHours; cout<<"\n\tTotalHours:"<<hours;}voidmain(){ CsStudentstudent1; charchInput[51]; intintInput;38 cout<<"Enterthefollowinginformation:\n"; cout<<"Name:"; cin.getline(chInput,51); student1.setName(chInput); cout<<"Numberofmathhourscompleted:"; cin>>intInput; student1.setMathHours(intInput); cout<<"NumberofCShourscompleted:"; cin>>intInput; student1.setCsHours(intInput); student1.setHours(); cout<<"\nSTUDENTINFORMATION\n"; student1.showInfo();}Student.hCsStudent.hCsStudent.cpp10-9.cpp39关于抽象类和纯虚函数小节如果一个类包含有纯虚函数,那么它就是抽象类,必须让其它类继承;基类中的纯虚函数没有代码;不能定义抽象类的对象,即抽象基类不能实例化;必须在子类中覆盖基类中的纯虚函数。4010.6.3指向基类的指针指向基类对象的指针可以指向其子类的对象;如果子类覆盖了基类中的成员,但通过基类指针所访问的成员仍是基类的成员,而不是子类成员。Example:例10-1041classBase{public:

voidshow(){cout<<"InBaseclass.\n";}};classDerived:publicBase{public:

voidshow(){cout<<"InDerivedclass.\n";}};voidmain(){ Base*bptr; Deriveddobject; bptr=&dobject; bptr->show();}10-10.cpp1.调用谁?2.什么原因?3.如何解决?4.引用调用呢?4210.7多重继承classAclassBclassCClassCinheritsallofClassB'smembers,includingtheonesClassBinheritedfromClassA.4310.8多继承如果一个子类具有两个或多个直接父类,那么就称为多继承。classAclassBclassCConstructorsarecalledintheordertheyarelistedinthefirstlineoftheclassdeclaration.44classDate //例10-12

{protected: intday,month,year;public: Date(intd,intm,inty) { day=d;month=m;year=y; } intgetDay(){returnday;} intgetMonth(){returnmonth;} intgetYear(){returnyear;}};45classTime{protected: inthour,min,sec;public: Time(inth,intm,ints) { hour=h;min=m;sec=s; } intgetHour(){returnhour;} intgetMin(){returnmin;} intgetSec(){returnsec;}};46classDateTime:publicDate,publicTime

{protected: chardTString[20];public:

DateTime(int,int,int,int,int,int); voidgetDateTime(char*str) { strcpy(str,dTString); }};这个顺序很重要47DateTime::DateTime(intyr,intmon,intdy,inthr,intmt,intsc):Time(hr,mt,sc),Date(dy,mon,yr)

{ chartemp[10];//IntheformYY/MM/DD strcpy(dTString,itoa(getYear(),temp,10)); strcat(dTString,"/"); strcat(dTString,itoa(getMonth(),temp,10)); strcat(dTString,"/"); strcat(dTString,itoa(getDay(),temp,10)); strcat(dTString,""); strcat(dTString,itoa(getHour(),temp,10)); strcat(dTString,":"); strcat(dTString,itoa(getMin(),temp,10)); strcat(dTString,":"); strcat(dTString,itoa(getSec(),temp,10));}48voidmain(){ charformatted[20]; DateTimepastDay(28,7,2010,11,32,27); pastDay.getDateTime(formatted); cout<<formatted<<endl;}Time.hDate.hDateTime.h

DateTime.cpp10-12.cpp49#include<ctime>#include<iostream>usingnamespacestd;voidmain(){chartmpbuf[128];//Displayoperatingsystem-styledateandtime_strtime(tmpbuf);cout<<"time:\t"<<tmpbuf<<endl;_strdate(tmpbuf);cout<<"date:\t"<<tmpbuf<<endl;}获取系统时间Ex10-a.cpp5010.9类模板类模板用于创立类属类和抽象数据类型,从而使程序员可以创立一般形式的类,而不必编写处理不同数据类型的类。类模板的定义和实现必须在同一个文件中,通常是头文件。编译器看到模板实现时才展开模板。Example:Program10-13.51template<classT>classFreewillArray{ T*aptr; intarraySize; voidmemError(void); //allocationerrors

voidsubError(void); //outofrangepublic: FreewillArray(){aptr=0;arraySize=0;} FreewillArray(int); FreewillArray(constFreewillArray&); ~FreewillArray(); intsize() {returnarraySize;}

T&operator[](constint&);};52//ConstructorforFreewillArrayclass.

template<classT>FreewillArray<T>::FreewillArray(ints){ arraySize=s; aptr=newT[s]

温馨提示

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

评论

0/150

提交评论