《C++程序設計教程》PPT Chapter-10_第1頁
《C++程序設計教程》PPT Chapter-10_第2頁
《C++程序設計教程》PPT Chapter-10_第3頁
《C++程序設計教程》PPT Chapter-10_第4頁
《C++程序設計教程》PPT Chapter-10_第5頁
已閱讀5頁,還剩53頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第10章繼承、多態(tài)和虛函數(shù)皮德常nuaacs@126.com110.1繼承繼承是OOP程序設計中很重要的一個方面。繼承易于擴充現(xiàn)有類以滿足新的應用。將已有的類稱之為父類,也稱基類,將新產(chǎn)生的類稱為子類,也稱為導出類或派生類。導出類不做任何改變地繼承了基類中的所有變量和函數(shù)(構造函數(shù)和析構函數(shù)除外),并且還可以增加新的數(shù)據(jù)成員和函數(shù),從而使導出類比基類更為特殊化。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"http://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"http://參數(shù)q代表問題的個數(shù),m代表答錯的題數(shù).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();}7上例中,父類中的公有成員在子類中仍是公有的,它們可以和子類中的公有成員一樣被訪問。但反過來是錯誤的,基類對象或基類中的某個函數(shù)不能調用子類中的函數(shù)。classBadBase

{ intx;public:

BadBase(){x=getVal();}//Error};classDerived:public

BadBase

{ inty;public: Derived(intz){y=z;}

int

getVal(){returny;}};810.2保護成員和類的訪問基類中的保護成員和私有成員比較類似,唯一的區(qū)別是:子類不可訪問基類中的私有成員,但可訪問基類中的保護成員。在公有繼承或保護繼承的情況下,子類能訪問基類的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();//新增加的函數(shù)};11//Contentsoftest2.cpp#include"test2.h"http://構造函數(shù)略voidTest::adjustScore(){ if((score-int(score))>=0.5f){ score+=0.5;

calcGrade(); }}who12繼承方式基類成員在子類中的表現(xiàn)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不要將繼承修飾符與成員的訪問修飾符相混淆:成員訪問修飾符是規(guī)定類外語句能否訪問類中的成員,而繼承修飾符是為了限定基類成員在子類中的表現(xiàn)。1510.3構造函數(shù)和析構函數(shù)當基類和子類都有構造函數(shù)時,如果定義一個子類對象,那么首先要調用基類的構造函數(shù),然后再調用子類的構造函數(shù);析構函數(shù)的調用次序與此相反,即先調用子類的析構函數(shù),然后再調用基類的析構函數(shù)。Example:

例10-3.16classBaseDemo{public:

BaseDemo() {cout<<"InBaseDemoconstructor.\n";} ~BaseDemo() {cout<<"InBaseDemodestructor.\n";}};classDeriDemo:publicBaseDemo{public:

DeriDemo() {cout<<"InDeriDemoconstructor.\n";} ~DeriDemo() {cout<<"InDeriDemodestructor.\n";}};17voidmain(){

cout<<"下面定義一個DerivedDemo

類對象\n";

DerivedDemoobject;//定義一個對象

cout<<"下面將要結束程序

\n";}Output:下面定義一個DerivedDemo

類對象調用基類BaseDemo的構造函數(shù)調用子類DerivedDemo

的構造函數(shù)下面將要結束程序調用子類DerivedDemo

的析構函數(shù)調用基類BaseDemo的析構函數(shù)1810.3.2向基類的構造函數(shù)傳參數(shù)如果基類和子類都有缺省的構造函數(shù),它們的調用是自動完成的,這是一種隱式調用。如果基類的構造函數(shù)帶有參數(shù),那么必須讓子類的構造函數(shù)顯式調用基類的構造函數(shù),并且向基類構造函數(shù)傳遞適當?shù)膮?shù)。

Example:例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;}21Note如果基類沒有缺省的構造函數(shù),那么子類必須至少具有一個帶參的構造函數(shù),以便向基類構造函數(shù)傳遞參數(shù)。2210.3.3初始化列表的作用1.

如果類之間具有繼承關系,子類必須在其初始化列表中調用基類的構造函數(shù)。例:classBase{ Base(intx);}; classDerived:publicBase{

Derived(intx,inty):Base(x)

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

類中的const常量只能在初始化列表中進行初始化,而不能在函數(shù)體內用賦值的方式來初始化。classBase{ constintSIZE;

Base(intsize):SIZE(size)

{/*…*/}};Baseone(100);2410.3.3初始化列表的作用3.

對象類型的成員的初始化放在初始化列表中,則效率較高,反之較低;基本類型變量的初始化可以在初始化列表中,也可在構造函數(shù)中,效率上沒區(qū)別。classBase{ Base();

Base(constBase&other);};classDerived{ BaseB_Member;public:

Derived(constBase&a);};構造函數(shù)的實現(xiàn):Derived::Derived(constBase&b):B_Member(b){/*…*/}也可這樣實現(xiàn),但效率較低。Derived::Derived(constBase&b){B_Member=b;}2510.4覆蓋基類的函數(shù)成員重載的特點:(1)重載表現(xiàn)為有多個函數(shù),它們的名字相同,但參數(shù)不全相同;(2)重載可以出現(xiàn)在同一個類中,也可出現(xiàn)在具有繼承關系的父類與子類中;(3)重載也可表現(xiàn)為外部函數(shù)的形式。2610.4覆蓋基類的函數(shù)成員覆蓋的特點:(1)覆蓋一定出現(xiàn)在具有繼承關系的基類和子類之間;(2)覆蓋除了要求函數(shù)名完全相同,還要求相應的參數(shù)個數(shù)和類型也完全相同;(3)當進行函數(shù)調用時,子類對象所調用的是子類中定義的函數(shù);(4)覆蓋是C++多態(tài)性的部分體現(xiàn)。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;

//Callbaseclassfunction

MileDist::setDist(feet/5280);}voidmain(){FeetDistfeet;floatft;

cout<<"Adistanceinfeetandconvertittomiles:";

cin>>ft;

feet.setDist(ft);

cout<<feet.getDist()<<"feetequals";

cout<<feet.getMiles()<<"miles.\n";}2910.5虛函數(shù)函數(shù)覆蓋體現(xiàn)了一定的多態(tài)性。但是,簡單的函數(shù)覆蓋并不能稱為真正的多態(tài)性。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<<"Adistanceinfeettomiles:";

cin>>ft;

feet.setDist(ft); cout.precision(1); cout.setf(ios::fixed);

cout<<feet.getDist()<<"feetequals";

cout<<feet.getMiles()<<"miles.\n";

cout<<feet.getDist()<<"squarefeetis";

cout<<feet.square()<<"totalfeet.\n";}33運行結果:

Adistanceinfeettomiles:52805280.0feetequals1.0miles.5280.0squarefeetis1.0totalfeet.錯誤的原因:C++編譯器在缺省情況下,對函數(shù)成員的調用實施的是靜態(tài)連編(也稱靜態(tài)綁定)。解決方法:將getDist設置為虛函數(shù)。對于虛函數(shù),編譯器完成的是動態(tài)連編(也稱動態(tài)綁定),即對函數(shù)的調用是在運行時確定的。OOP:

覆蓋和重載不能體現(xiàn)真正的多態(tài)性,只有虛函數(shù)才是多態(tài)性的表現(xiàn)。不支持多態(tài)性的語言,就不能稱為OOP。3410.6純虛函數(shù)和抽象類純虛函數(shù)是在基類中聲明的虛函數(shù),沒有函數(shù)體,要求繼承基類的子類必須覆蓋它。帶有純虛函數(shù)的類稱為抽象類,不能定義抽象類的對象。派生類可以根據(jù)自己的需要,分別覆蓋它,從而實現(xiàn)真正意義上的多態(tài)性。格式: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{ int

mathHours,csHours;public: voidsetMathHours(int

mh){mathHours=mh;} voidsetCsHours(int

csh){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];

int

intInput;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();}39Rememberthefollowingpoints如果一個類包含有純虛函數(shù),那么它就是抽象類,必須讓其它類繼承它;基類中的純虛函數(shù)沒有代碼;不能定義抽象類的對象,即抽象基類不能實例化;必須在子類中覆蓋基類中的純虛函數(shù)。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();}思考:調用誰?什么原因?如何解決?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; }

int

getDay(){returnday;}

int

getMonth(){returnmonth;}

int

getYear(){returnyear;}};45classTime{protected:

inthour,min,sec;public:

Time(inth,intm,ints) { hour=h;min=m;sec=s; }

int

getHour(){returnhour;}

int

getMin(){returnmin;}

int

getSec(){returnsec;}};46classDateTime:publicDate,publicTime

{protected: chardTString[20];public:

DateTime(int,int,int,int,int,int); voidgetDateTime(char*str) {

strcpy(str,dTString); }};這個順序很重要47DateTime::DateTime(int

yr,int

mon,int

dy,inthr,

int

mt,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];

DateTime

pastDay(2,4,60,5,32,27);

pastDay.getDateTime(formatted);

cout<<formatted<<endl;}輸出結果:

4/2/605:32:2749#include<time.h>#include<iostream.h>voidmain(){chartmpbuf[128];//Displayoperatingsystem-styledateandtime_strtime(tmpbuf);

cout<<"time:\t"<<tmpbuf<<endl;_strdate(tmpbuf);

cout<<"date:\t"<<tmpbuf<<endl;}獲取系統(tǒng)時間5010.9類模板類模板用于創(chuàng)建類屬類和抽象數(shù)據(jù)類型,從而使程序員可以創(chuàng)建一般形式的類,而不必編寫處理不同數(shù)據(jù)類型的類。

Example:Program10-13.51template<classT>classFreewillArray{ T*aptr;

int

arraySize; voidmemError(void); //allocationerrors

voidsubError(void); //outofrangepublic:

FreewillArray(){aptr=0;arraySize=0;}

FreewillArray(int);

FreewillArray(const

FreewillArray&); ~FreewillArray();

intsize() {returnarraySize;}

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

template<classT>FreewillArray<T>::FreewillArray(ints){

arraySize=s;

aptr=newT[s]; if(aptr

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論