單繼承與多態(tài)_第1頁(yè)
單繼承與多態(tài)_第2頁(yè)
單繼承與多態(tài)_第3頁(yè)
單繼承與多態(tài)_第4頁(yè)
單繼承與多態(tài)_第5頁(yè)
已閱讀5頁(yè),還剩52頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

面向?qū)ο蟪绦蛟O(shè)計(jì)(C++)

OrientedObjectProgramming(C++)

第七章繼承和多態(tài)第七章繼承和多態(tài)繼承是C++語(yǔ)言的一種重要機(jī)制,該機(jī)制自動(dòng)地為一個(gè)類提供來自另一個(gè)類的操作和數(shù)據(jù)結(jié)構(gòu),這使得程序員只需在新類中定義已有類中沒有的成分來建立新類。通過學(xué)習(xí)本章,能利用繼承現(xiàn)有的類建立新類,能理解繼承如何提高軟件的重用性,理解多態(tài)性對(duì)于繼承的意義,掌握多態(tài)的工作原理,理解抽象類和具體類的區(qū)別,學(xué)會(huì)運(yùn)用純虛函數(shù)。第七章繼承和多態(tài)§7-1繼承§7-2多態(tài)性§7-3抽象類§7-1繼承

7.1.1

繼承的概念

在C++中,可以利用已有的類來定義新的類,新類將擁有原有類的全部特性,原有類被稱為基類(Baseclass)或父類(Superclass),新產(chǎn)生的類被稱為派生類(Derivedclass)或子類(Subclass)。派生類擁有基類的特性稱作繼承,由基類產(chǎn)生派生類的過程稱為派生。

每一個(gè)派生類都有且僅有一個(gè)基類,派生類可以看作是基類的特例,它增加了某些基類所沒有的性質(zhì)。這種繼承方式,稱為單繼承或單向繼承。現(xiàn)實(shí)生活中,子女的外貌、血型往往不是僅僅繼承自父親或母親,而是將父母親的特點(diǎn)都繼承下來。與之相類似,如果一個(gè)派生類有兩個(gè)或兩個(gè)以上的基類,則稱為多繼承或多重繼承。

派生類又作為基類,繼續(xù)派生新的類,這樣的派生方式稱為多層派生,從繼承的角度看稱為多層繼承?!?-1繼承分類層次圖派生類定義的語(yǔ)法為:

class派生類名:繼承方式1基類名1,繼承方式2基類名2,…{private:

派生類的私有數(shù)據(jù)和函數(shù)

public:

派生類的公有數(shù)據(jù)和函數(shù)

protected:

派生類的保護(hù)數(shù)據(jù)和函數(shù)};7.1.2派生類實(shí)現(xiàn)1.派生類的定義“繼承方式1基類名1,繼承方式2基類名2,…”為基類名表,表示當(dāng)前定義的派生類的各個(gè)基類。7.1.2派生類實(shí)現(xiàn)如果基類名表中只有一個(gè)基類,表示定義的是單繼承;如果基類名表中有多個(gè)基類,表示定義的是多繼承。繼承方式指定了派生類成員以及類外對(duì)象對(duì)于從基類繼承來的成員的訪問權(quán)限。繼承方式有三種:

public:公有繼承;private:私有繼承;protected:保護(hù)繼承

7.1.2派生類實(shí)現(xiàn)classClock{private:intH,M,S;public:voidSetTime(intH=0,intM=0,intS=0); voidShowTime(); Clock(intH=0,intM=0,intS=0); ~Clock();};classAlarmClock:publicClock{private:intAH,AM;//響鈴的時(shí)間

boolOpenAlarm;//是否關(guān)閉鬧鐘public:voidSetAlarm(intAH,intAM);//設(shè)置響鈴時(shí)間

voidSwitchAlarm(boolOpen=true);//打開/關(guān)閉鬧鈴

voidShowTime();//顯示當(dāng)前時(shí)間與鬧鈴時(shí)間}在派生類的定義中,每一種繼承方式只限定緊跟其后的那個(gè)基類。如果不顯式給出繼承方式,系統(tǒng)默認(rèn)為私有繼承。

【例如】在普通的時(shí)鐘類Clock基礎(chǔ)上派生出鬧鐘類AlarmClock:類名成員名AlarmClock::Clock::H,M,SSetTime()ShowTime()AH,AM,OpenAlarmSetAlarm()SwitchAlarm()ShowTime()AlarmClock()派生類AlarmClock的成員構(gòu)成圖(表)7.1.2派生類實(shí)現(xiàn)2.派生類的實(shí)現(xiàn)方式

(1)吸收基類成員

基類的全部成員被派生類繼承,作為派生類成員的一部分。如:Clock類中的數(shù)據(jù)成員H、M、S,成員函數(shù)SetTime()、ShowTime()經(jīng)過派生,成為派生類AlarmClock的成員。

(2)改造基類成員派生類根據(jù)實(shí)際情況對(duì)繼承自基類的某些成員進(jìn)行限制和改造。對(duì)基類成員的訪問限制主要通過繼承方式來實(shí)現(xiàn);對(duì)基類成員的改造主要通過同名覆蓋來實(shí)現(xiàn),即在派生類中定義一個(gè)與基類成員同名的新成員(如果是成員函數(shù),則函數(shù)參數(shù)表也必須相同,否則,C++會(huì)認(rèn)為是函數(shù)重載)。當(dāng)通過派生類對(duì)象調(diào)用該成員時(shí),C++將自動(dòng)調(diào)用派生類中重新定義的同名成員,而不會(huì)調(diào)用從基類中繼承來的同名成員,這樣派生類中的新成員就“覆蓋”了基類的同名成員。由此可見,派生類中的成員函數(shù)具有比基類中同名成員函數(shù)更小的作用域。如:AlarmClock類中的成員函數(shù)ShowTime()覆蓋了基類Clock中的同名成員函數(shù)ShowTime()。7.1.2派生類實(shí)現(xiàn)(3)添加新成員派生類在繼承基類成員的基礎(chǔ)之上,根據(jù)派生類的實(shí)際需要,增加一些新的數(shù)據(jù)成員和函數(shù)成員,以描述某些新的屬性和行為。如:AlarmClock添加了數(shù)據(jù)成員AH、AM、OpenAlarm,成員函數(shù)SetAlarm()、SwitchAlarm()。7.1.2派生類實(shí)現(xiàn)3.繼承的性質(zhì)

(1)繼承關(guān)系是可以傳遞的在派生過程中,一個(gè)基類可以同時(shí)派生出多個(gè)派生類,派生出來的新類也同樣可以作為基類再繼續(xù)派生新的派生類。這樣,就形成了一個(gè)相互關(guān)聯(lián)的類的家族,有時(shí)也稱作類族。在類族中,直接派生出某類的基類稱為直接基類,基類的基類甚至更高層的基類稱為間接基類,比如類A派生出類B,類B又派生出類C,則類B是類C的直接基類,類A是類B的直接基類,而類A稱為類C的間接基類。

(2)繼承關(guān)系不允許循環(huán)在派生過程中,不允許類A派生出類B,類B又派生出類C,而類C又派生出類A。7.1.3繼承與組合

繼承描述的是一般類與特殊類的關(guān)系,類與類之間體現(xiàn)的是“isakindof”,即如果在邏輯上A是B的一種(isakindof),則允許A繼承B的功能和屬性。例如汽車(automobile)是交通工具(vehicle)的一種,小汽車(car)是汽車的一種。那么類automobile可以從類vehicle派生,類car可以從類automobile派生。

類以另一個(gè)類對(duì)象做數(shù)據(jù)成員,成為組合。組合描述的是整體與部分的關(guān)系,類與類之間體現(xiàn)的是“isapartof”,即如果在邏輯上A是B的一部分(isapartof),則允許A和其他數(shù)據(jù)成員組合為B。例如:發(fā)動(dòng)機(jī)、車輪、電池、車門、方向盤、底盤都是小汽車的一部分,它們組合成汽車。而不能說發(fā)動(dòng)機(jī)是汽車的一種。7.1.3繼承與組合

繼承和組合既有區(qū)別,也有聯(lián)系,某些比較復(fù)雜的類,既需要使用繼承,也需要使用組合,二者一起使用。在某些情況下,繼承與組合的實(shí)現(xiàn)還可以互換。在多繼承時(shí),一個(gè)派生類有多個(gè)直接基類,派生類實(shí)際上是所有基類屬性和行為的組合。派生類是對(duì)基類的擴(kuò)充,派生類成員一部分是從基類中來,因此派生類組合了基類。既然這樣,派生類也可以通過組合類實(shí)現(xiàn)。例如:AlarmClock類可以通過組合Clock類實(shí)現(xiàn),從功能上講,基本的時(shí)鐘功能是鬧鐘功能的一部分。什么時(shí)候使用繼承,什么時(shí)候使用組合,要根據(jù)問題類與類之間的具體關(guān)系,順其自然,權(quán)衡考慮。例:p354

7.1.4繼承的方式p389

①基類的公有成員在派生類中仍然為公有成員,可以由派生類對(duì)象和派生類成員函數(shù)直接訪問。

基類的私有成員在派生類中,無論是派生類的成員還是派生類的對(duì)象都無法直接訪問。

保護(hù)成員在派生類中仍是保護(hù)成員,可以通過派生類的成員函數(shù)訪問,但不能由派生類的對(duì)象直接訪問。7.1.4公有繼承公有方式繼承的特點(diǎn):

注意:對(duì)基類成員的訪問,一定要分清是通過派生類對(duì)象訪問還是通過派生類成員函數(shù)訪問。

【例7-1】公有繼承及其訪問將點(diǎn)理解為半徑長(zhǎng)度為0的圓,Point(點(diǎn))類公有派生出新的Circle(圓)類。圓類具備Point類的全部特征,同時(shí)自身也有自己的特點(diǎn):圓有半徑。7.1.4公有繼承123456789101112131415161718192021//Point.h#include<iostream>usingnamespacestd;classPoint{private: intX,Y;public: Point(intX=0,intY=0) {this->X=X,this->Y=Y; } voidmove(intOffX,intOffY) {X+=OffX,Y+=OffY; } voidShowXY() { cout<<"("<<X<<","<<Y<<")"<<endl; }};7.1.4公有繼承1234567891011121314151617181920212223242526/*******************************Circle.h**從Point類派生出圓類(Circle)********************************/#include"point.h"constdoublePI=3.14159;classCircle:publicPoint{private: doubleradius;//半徑public:

Circle(doubleR,intX,intY):Point(X,Y){ radius=R;}doublearea()//求面積

{returnPI*radius*radius;}

voidShowCircle(){cout<<"Centreofcircle:";ShowXY();cout<<"radius:"<<radius<<endl;}};類名成員名訪問權(quán)限CirclePoint::X,Yprivate不可訪問move()publicpublicShowXY()publicpublicradiusprivatearea()publicShowCircle()publicCircle()public7.1.4公有繼承313233343536373839404142434445/***********************p8_1.cpp**Circle類的使用************************/#include"Circle.h"usingnamespacestd;intmain(){CircleCir1(10,100,200); Cir1.ShowCircle();cout<<"areais:"<<Cir1.area()<<endl; Cir1.move(10,20);Cir1.ShowXY();return0;}運(yùn)行結(jié)果Centreofcircle:(100,200)

radius:10

areais:31415.9

(110,220)

P389例子7.1.4公有繼承1234567891011121314151617181920212223242526/*******************************Circle.h**從Point類派生出圓類(Circle)********************************/#include"point.h"constdoublePI=3.14159;classCircle:publicPoint{private: doubleradius;//半徑public:

Circle(intX,intY,doubleR):Point(X,Y)

{ radius=R;}

doublearea()//求面積

{ returnPI*radius*radius;}

voidShowCircle(){cout<<"Centreofcircle:";ShowXY();cout<<"radius:"<<radius<<endl;}};程序解釋

派生類Circle繼承了Point類的除構(gòu)造函數(shù)外的全部成員,擁有從基類繼承過來的成員與派生類新添加的成員的總和。繼承方式為公有繼承,這時(shí),基類中的公有成員在派生類中訪問屬性保持原樣,派生類的成員函數(shù)及對(duì)象可以訪問基類派生的的公有成員?;愒械耐獠拷涌?公有成員函數(shù)),如ShowXY()和move()變成了派生類外部接口的一部分。在Circle的構(gòu)造函數(shù)中,為了給從基類繼承來的數(shù)據(jù)成員賦初值,使用了初始化列表,其格式與組合類相同7.1.5私有繼承

①基類的公有成員和保護(hù)成員被繼承后作為派生類的私有成員,即基類的公有成員和保護(hù)成員被派生類吸收后,派生類的其他成員函數(shù)可以直接訪問它們,但是在類外部,不能通過派生類的對(duì)象訪問它們。

②基類的私有成員在派生類中不能被直接訪問。無論是派生類的成員還是通過派生類的對(duì)象,都無法訪問從基類繼承來的私有成員。

③經(jīng)過私有繼承之后,所有基類的成員都成為了派生類的私有成員或不可訪問的成員,如果進(jìn)一步派生的,基類的全部成員將無法在新的派生類中被訪問。因此,私有繼承之后,基類的成員再也無法在以后的派生類中發(fā)揮作用,實(shí)際是相當(dāng)于中止了基類的繼續(xù)派生,出于這種原因,一般情況下私有繼承的使用比較少。私有方式繼承的特點(diǎn):

【例7-2】私有繼承派生類的實(shí)現(xiàn)及其訪問7.1.5私有繼承//Circle2.h#include"point.h"constdoublePI=3.14159;classCircle:privatePoint{private: doubleradius;//半徑

public: Circle(doubleR,intX,intY):Point(X,Y) {radius=R; } doublearea()//求面積

{returnPI*radius*radius;} voidShowCircle() {cout<<"Centreofcircle:";ShowXY();cout<<"radius:"<<radius<<endl; } voidmove(intOffX,intOffY) {Point::move(OffX,OffY); }};類名成員名訪問權(quán)限CirclePoint::X,Yprivate不可訪問move()publicprivateShowXY()publicprivateradiusprivatearea()publicShowCircle()publicCircle()publicCircle2.h的完整程序如課件所示。7.1.5私有繼承運(yùn)行結(jié)果Centreofcircle:(100,200)

radius:10

areais:31415.9#include"Circle2.h"usingnamespacestd;intmain(){ CircleCir1(10,100,200); Cir1.ShowCircle(); cout<<"areais:"<<Cir1.area()<<endl; Cir1.move(10,20);//同名覆蓋

//Cir1.ShowXY();//錯(cuò)誤,ShowXY()繼承為私有成員函數(shù)

return0;}程序解釋對(duì)比兩個(gè)示例程序,可以看出:由于是私有繼承,基類中的所有成員在派生類中都成為私有成員,因此派生類對(duì)象不能直接訪問任何一個(gè)基類的成員。類Circle的對(duì)象Cir1調(diào)用的都是派生類自身的公有成員。本例僅僅對(duì)派生類的實(shí)現(xiàn)作了適當(dāng)?shù)男薷模惡椭鞒绦虿糠譀]有做任何改動(dòng),程序運(yùn)行的結(jié)果同前例。由此可見面向?qū)ο蟪绦蛟O(shè)計(jì)封裝性的優(yōu)越性,這正是面向?qū)ο蟪绦蛟O(shè)計(jì)可重用與可擴(kuò)充性的一個(gè)實(shí)際體現(xiàn)。P392例子7.1.6保護(hù)繼承

①基類的公有成員和保護(hù)成員被繼承后作為派生類的保護(hù)成員。

②基類的私有成員在派生類中不能被直接訪問。即派生類的其它成員函數(shù)可以直接訪問基類的公有成員和保護(hù)成員,但是在類的外部通過派生類的對(duì)象無法訪問它們。修改Circle2.h,將派生類的繼承方式改為保護(hù)繼承,其它部分不變:保護(hù)繼承的特點(diǎn):

//circle3.h#include“piont.h”classCircle:protectedpoint{//類成員定義}類名成員名訪問權(quán)限CirclePoint::X,Yprivate不可訪問move()publicprotectedShowXY()publicprotectedradiusprivatearea()publicShowCircle()publicCircle()public7.1.6保護(hù)繼承運(yùn)行結(jié)果Centreofcircle:(100,200)

radius:10

areais:31415.9

#include"Circle3.h"usingnamespacestd;intmain(){ CircleCir1(10,100,200); Cir1.ShowCircle(); cout<<"areais:"<<Cir1.area()<<endl; Cir1.move(10,20);//同名覆蓋

//Cir1.ShowXY();//錯(cuò)誤,ShowXY()繼承為保護(hù)成員函數(shù)

return0;}程序解釋:private、protected兩種繼承方式下,基類所有成員在派生類中的訪問屬性都是完全相同的。即在派生類中可以訪問基類的公有、保護(hù)成員不可訪問基類的私有成員。如果將派生類作為新的基類繼續(xù)派生時(shí),private、protected兩種繼承方式區(qū)別就出現(xiàn)了。假設(shè)類B以私有方式繼承自類A,則無論B類以什么方式派生出類C,類C的成員和對(duì)象都不能訪問間接從A類中繼承來的成員。但如果類B是以保護(hù)方式繼承自類A,那么類A中的公有和保護(hù)成員在類B中都是保護(hù)成員。類B再派生出類C后,如果是公有派生或保護(hù)派生,則類A中的公有和保護(hù)成員被類C間接繼承后,類C的成員函數(shù)可以訪問間接從類A中繼承來的成員。即類A的成員可以沿繼承樹繼續(xù)向下傳播。

【例7-2

】保護(hù)繼承與保護(hù)成員的訪問修改例8-1,除將基類Point的數(shù)據(jù)成員X和Y的訪問屬性改為protected外,又增加了一個(gè)派生類:Cylinder(圓柱體)類。Cylinder類保護(hù)繼承自類circle。程序?qū)崿F(xiàn)如下:

7.1.6保護(hù)繼承123456789101112131415161718192021//Point2.h#include<iostream>usingnamespacestd;classPoint{protected: intX,Y;public:

Point(intX=0,intY=0) {this->X=X,this->Y=Y; }

voidmove(intOffX,intOffY) {X+=OffX,Y+=OffY; }

voidShowXY() { cout<<"("<<X<<","<<Y<<")"<<endl; }};7.1.6保護(hù)繼承1234567891011121314151617181920212223242526272829303132/**********************************p7_2.cpp**從circle類派生出圓柱類(Cylinder)**********************************/#include"point2.h"constdoublePI=3.14159;classCircle:protectedPoint{protected: doubleradius;//半徑public:

Circle(doubleR,intX,intY):Point(X,Y) { radius=R; }

doublearea()//求面積

{ returnPI*radius*radius;}

voidShowCircle() {cout<<"Centreofcircle:";ShowXY();cout<<"radius:"<<radius<<endl; }};classCylinder:protectedCircle{private: doubleheight;public:

Cylinder(intX,intY,doubleR,doubleH):Circle(R,X,Y)

333435363738394041424344454647484950515253545556 { height=H; }

doublearea() {return2*Circle::area()+2*PI*radius*height; }

doublevolume() { returnCircle::area()*height; }

voidShowCylinder() {ShowCircle();

cout<<"heightofcylinder:"<<height<<endl; }};voidmain(){CylinderCY(100,200,10,50); CY.ShowCylinder();

cout<<"totalarea:"<<CY.area()<<endl; cout<<"volume:"<<CY.volume();}運(yùn)行結(jié)果Centreofcircle:(100,200)

radius:10

heightofcylinder:50

totalarea:3769.11

volume:15707.9

7.1.6保護(hù)繼承1234567891011121314151617181920212223242526272829303132/**********************************p8_2.cpp**從circle類派生出圓柱類(Cylinder)**********************************/#include"point2.h"constdoublePI=3.14159;classCircle:protectedPoint{protected: doubleradius;//半徑public:

Circle(doubleR,intX,intY):Point(X,Y) { radius=R; }

doublearea()//求面積

{ returnPI*radius*radius;}

voidShowCircle() {cout<<"Centreofcircle:";ShowXY();cout<<"radius:"<<radius<<endl; }};classCylinder:protectedCircle{private: doubleheight;public:

Cylinder(intX,intY,doubleR,doubleH):Circle(R,X,Y)

333435363738394041424344454647484950515253545556 { height=H; }

doublearea() {return2*Circle::area()+2*PI*radius*height; }

doublevolume() { returnCircle::area()*height; }

voidShowCylinder() {ShowCircle();

cout<<"heightofcylinder:"<<height<<endl; }};voidmain(){CylinderCY(100,200,10,50); CY.ShowCylinder();

cout<<"totalarea:"<<CY.area()<<endl; cout<<"volume:"<<CY.volume();}Circle保護(hù)繼承自類Point,因此類Circle為子類,類Point為父類,對(duì)于該子類來講,保護(hù)成員與公有成員具有相同的訪問特性。所以派生類的成員函數(shù)ShowCircle()可以訪問基類從基類繼承而來的保護(hù)成員,當(dāng)然它也可以調(diào)用從基類繼承來的公有成員函數(shù)ShowXY()。

類Circle沿類的繼承樹繼續(xù)派生出類Cylinder,繼承方式依然為保護(hù)繼承,因此,在類cylinder中,它間接從類Point中繼承了四個(gè)保護(hù)成員:數(shù)據(jù)成員X、Y,以及成員函數(shù)move()、ShowXY();同時(shí)它也直接從其父類Circle中繼承了3個(gè)類成員:數(shù)據(jù)成員radius,成員函數(shù)ShowCircle()、area(),它們都以保護(hù)成員的身份出現(xiàn)在類Cylinder中。因此,在類Cylinder的成員函數(shù)ShowCylinder()中,不僅可以訪問從父類Circle中直接繼承來的成員函數(shù)ShowCircle(),而且可以訪問沿繼承樹從基類Point中間接繼承來的數(shù)據(jù)成員X和Y。

當(dāng)通過類Cylinder的對(duì)象CY調(diào)用成員函數(shù)area()時(shí),由于對(duì)象CY擁有兩個(gè)同名成員函數(shù)area(),一個(gè)是從其父類Circle繼承來的,一個(gè)是類Cylinder自己新增的,二者函數(shù)體實(shí)現(xiàn)完全不同。類Circle的成員函數(shù)area()和派生類Cylinder新增的成員函數(shù)area()都具有類作用域,二者的作用范圍不同,是相互包含的兩個(gè)層,派生類在內(nèi)層。由于,派生類Cylinder聲明了一個(gè)和其父類circle成員同名的新成員area(),派生的新成員函數(shù)就覆蓋了外層父類的同名成員函數(shù),直接使用成員名只能訪問到派生類自己新增的同名成員函數(shù)。C++利用同名覆蓋原則,自動(dòng)選擇調(diào)用類Cylinder新增的成員函數(shù)area(),輸出圓柱體的總的表面積,這再一次體現(xiàn)了繼承機(jī)制所產(chǎn)生的程序重用性和可擴(kuò)充性。7.1.6保護(hù)繼承三種繼承方式下,基類成員在派生類中的訪問控制屬性總結(jié)如圖:

基類屬性繼承方式publicprotectedprivatepublicpublicprotected不可訪問protectedprotectedprotected不可訪問privateprivateprivate不可訪問7.1.7派生類的構(gòu)造與析構(gòu)

當(dāng)使用派生類建立一個(gè)派生類對(duì)象時(shí),將首先產(chǎn)生一個(gè)基類對(duì)象,依附于派生類對(duì)象中。如果派生類新增成員中還包括內(nèi)嵌的其它類對(duì)象,派生類的數(shù)據(jù)成員中實(shí)際上還間接包括了這些對(duì)象的數(shù)據(jù)成員,因此,構(gòu)造派生類對(duì)象時(shí),就要對(duì)基類數(shù)據(jù)成員,新增數(shù)據(jù)成員和成員對(duì)象的數(shù)據(jù)成員進(jìn)行初始化。在派生類對(duì)象的成員中,從基類繼承來的成員被封裝為基類子對(duì)象,他們的初始化由派生類構(gòu)造函數(shù)隱含調(diào)用基類構(gòu)造函數(shù)進(jìn)行初始化;內(nèi)嵌成員對(duì)象則隱含調(diào)用成員類的構(gòu)造函數(shù)予以初始化;派生類新增的數(shù)據(jù)成員由派生類在自己定義的構(gòu)造函數(shù)中進(jìn)行初始化;7.1.7派生類的構(gòu)造與析構(gòu)

1.派生類構(gòu)造函數(shù)的定義

派生類名(參數(shù)總表):基類名1(參數(shù)表1),...,基類名m(參數(shù)表m),成員對(duì)象名1(成員對(duì)象參數(shù)表1),...,成員對(duì)象名n(成員對(duì)象參數(shù)表n){

派生類新增成員的初始化;

}

基類名1(參數(shù)表1),...,基類名m(參數(shù)表m)稱為基類成員的初始化表。成員對(duì)象名1(成員對(duì)象參數(shù)表1),...,成員對(duì)象名n(成員對(duì)象參數(shù)表n)

為成員對(duì)象的初始化表?;惓蓡T的初始化表與成員對(duì)象的初始化表構(gòu)成派生類構(gòu)造函數(shù)的初始化表。在派生類構(gòu)造函數(shù)的參數(shù)總表中,需要給出基類數(shù)據(jù)成員的初值、成員對(duì)象數(shù)據(jù)成員的初值、新增一般數(shù)據(jù)成員的初值。在參數(shù)總表之后,列出需要使用參數(shù)進(jìn)行初始化的基類名、成員對(duì)象名及各自的參數(shù)表,各項(xiàng)之間使用逗號(hào)分隔?;惷?、對(duì)象名之間的次序無關(guān)緊要,它們各自出現(xiàn)的順序可以是任意的。在生成派生類對(duì)象時(shí),程序首先會(huì)使用這里列出的參數(shù),調(diào)用基類和成員對(duì)象的構(gòu)造函數(shù)。。7.1.7派生類的構(gòu)造與析構(gòu)

什么時(shí)候需要定義派生類的構(gòu)造函數(shù)?

如果基類定義了帶有形參表的構(gòu)造函數(shù)時(shí),派生類就應(yīng)當(dāng)定義構(gòu)造函數(shù),提供一個(gè)將參數(shù)傳遞給基類構(gòu)造函數(shù)的途徑,保證在基類進(jìn)行初始化時(shí)能夠獲得必要的數(shù)據(jù)。①

調(diào)用基類構(gòu)造函數(shù);②

調(diào)用內(nèi)嵌成員對(duì)象的構(gòu)造函數(shù),調(diào)用順序按照它們?cè)陬愔卸x的順序。③

派生類自己的構(gòu)造函數(shù)。

如果基類沒有定義構(gòu)造函數(shù),派生類也可以不定義構(gòu)造函數(shù),全部采用默認(rèn)的構(gòu)造函數(shù),這時(shí)新增成員的初始化工作可以用其他公有成員函數(shù)來完成。2單繼承的構(gòu)造與析構(gòu)單繼承時(shí),派生類構(gòu)造函數(shù)調(diào)用的一般次序如下:④當(dāng)派生類對(duì)象析構(gòu)時(shí),各析構(gòu)函數(shù)的調(diào)用順序正好相反。首先調(diào)用派生類析構(gòu)函數(shù)(清理派生類新增成員);然后調(diào)用派生類成員對(duì)象析構(gòu)函數(shù)(清理派生類新增的成員對(duì)象);最后調(diào)用基類析構(gòu)函數(shù)(清理從基類繼承來的基類子對(duì)象)。例p352例ch16-1p350classstudent{……private:charname[10];floataverage;};classGraduateStudent:publicstudent{……private:intqualifierGrade;};在構(gòu)造一個(gè)子類時(shí),完成其基類部分的構(gòu)造由基類構(gòu)造函數(shù)去做。從Student繼承部分(14字節(jié))GraduateStudent特有部分(2字節(jié))thisGraduateStudent對(duì)象(共16字節(jié))§7-1繼承

派生類的構(gòu)造順序classGraduateStudent:publicStudent

{public:

GraduateStudent(char*pName,Advisor&adv):Student(pName),advisor(adv)

{qualiferGrade=0;}

protected:

Advisoradvisor;

intqualiferGrade;

};

voidfn(Advisor&advisor)

{GraduateStudentgs(“YenKayDoodle”,advisor);}

voidmain()

{Advisorda;

fn(da);

}共構(gòu)造了兩個(gè)Advisor對(duì)象,一個(gè)Student對(duì)象,一個(gè)GraduateStudent對(duì)象7.1.7派生類的構(gòu)造與析構(gòu)

【例8-3】單繼承的構(gòu)造與析構(gòu)。

為了說明單繼承的構(gòu)造,由Point類派生出Circle類,再由兩個(gè)同心Circle類對(duì)象與高度height構(gòu)成空管Tube類。構(gòu)成空管的兩個(gè)同心圓的外圓從Circle類繼承,內(nèi)圓組合Circle類對(duì)象InCircle。Tube類的層次結(jié)構(gòu)圖如圖:7.1.7派生類的構(gòu)造與析構(gòu)

123456789101112131415161718192021222324252627282930313233343536/*******************************p8_3.cpp**多層繼承的構(gòu)造函數(shù)與析構(gòu)函數(shù)*******************************/#include<iostream>usingnamespacestd;classPoint{private: intX,Y;public:

Point(intX=0,intY=0) {this->X=X,this->Y=Ycout<<"point("<<X<<","<<Y<<")constructing..."<<endl; }

~Point() {cout<<"point("<<X<<","<<Y<<")destructing..."<<endl; }};classCircle:protectedPoint{protected: doubleradius;//半徑public:Circle(doubleR=0,intX=0,intY=0):Point(X,Y) { radius=R; cout<<"circleconstructing,radius:"<<R<<endl; }

~Circle() { cout<<"circledestructing,radius:"<<radius<<endl; }};37383940414243444546474849505152535455565758classtube:protectedCircle{private:doubleheight;CircleInCircle;public:tube(doubleH,doubleR1,doubleR2=0,intX=0,intY=0):InCircle(R2,X,Y),Circle(R1,X,Y){height=H;cout<<"tubeconstructing,height:"<<H<<endl; }

~tube(){cout<<"tubedestructing,height:"<<height<<endl;}};intmain(){tubeTU(100,20,5);return0;}運(yùn)行結(jié)果point(0,0)constructing...

circleconstructing,radius:20

point(0,0)constructing...

circleconstructing,radius:5

tubeconstructing,height:100

tubedestructing,height:100

circledestructing,radius:5

point(0,0)destructing...

circledestructing,radius:20

point(0,0)destructing...

定義了一個(gè)派生類Tube的對(duì)象TU,首先試圖調(diào)用類Tube的構(gòu)造函數(shù);類Tube是派生類,由基類Circle派生,于是試圖調(diào)用Circle類的構(gòu)造函數(shù);

類Circle的基類是Point,沿繼承樹上溯至頂層基類Point,調(diào)用Point類的構(gòu)造函數(shù);

Tube同時(shí)又是一個(gè)組合類,由對(duì)象InCircle組合而成,于是,再?gòu)捻攲踊怭oint開始,依次調(diào)用調(diào)用Point類的構(gòu)造函數(shù)、Circle的構(gòu)造函數(shù)。

當(dāng)退出主函數(shù)之前,程序沿繼承樹自底向上依次調(diào)用各類的析構(gòu)函數(shù),其順序與構(gòu)造函數(shù)順序正好相反。

在C++中,類型兼容主要指以下三種情況:

①派生類對(duì)象可以賦值給基類對(duì)象。

②派生類對(duì)象可以初始化基類的引用。

③派生類對(duì)象的地址可以賦給指向基類的指針。7.1.8類型兼容

類型兼容是指在公有派生的情況下,一個(gè)派生類對(duì)象可以作為基類的對(duì)象來使用的情況。類型兼容又稱為類型賦值兼容或類型適應(yīng)。

【例8-4】演示類的兼容性。前面我們定義了類Point,它公有派生出類Circle,后者進(jìn)一步公有派生出類Cylinder。我們可以通過這個(gè)單繼承的例子來驗(yàn)證類型兼容規(guī)則。運(yùn)行結(jié)果(1,1)

(20,20)

(300,300)

(300,300)

(20,20)

8.4類型兼容123456789101112131415161718192021222324252627282930313233343536373839/***************************************p8_4.cpp**從circle類公有派生出圓柱類Cylinder**演示類的兼容性***************************************/#include"Circle.h"classCylinder:publicCircle{private: doubleheight;public:

Cylinder(doubleR,intX,intY,doubleH):Circle(R,X,Y) { height=H; }voidShowCylinder() {ShowCircle(); cout<<"heightofcylinder:"<<height<<endl; }};intmain(){PointP(1,1);//Point類對(duì)象

CircleCir(15,20,20);//Circle類對(duì)象

CylinderCY(15,300,300,50);//Cylinder類對(duì)象

Point*Pp;//point類指針

Pp=&P;//將基類對(duì)象地址賦給指向基類的指針

Pp->ShowXY();Pp=&Cir;//將派生類對(duì)象地址賦給指向基類的指針

Pp->ShowXY();Pp=&CY;//將派生類對(duì)象地址賦給指向基類的指針

Pp->ShowXY();Circle&RC=CY;//Circle類引用引用了派生類Cylinder對(duì)象

RC.ShowXY();P=Cir;//Circle類對(duì)象賦值給基類Point類對(duì)象

P.ShowXY();return0;}定義了Point類型的指針Pp指向了Point類對(duì)象指向了Circle類對(duì)象指向了Cylinder類對(duì)象Pp調(diào)用了Point類的成員函數(shù)ShowXY(),顯示了Point類對(duì)象的中心坐標(biāo)值。調(diào)用了Point類的成員函數(shù)ShowXY(),顯示了Circle類對(duì)象的中心坐標(biāo)值。調(diào)用了Point類的成員函數(shù)ShowXY(),顯示了Cylinder類對(duì)象的中心坐標(biāo)值。P8_4.cpp的正確程序和運(yùn)行結(jié)果如課件所示,注意構(gòu)造函數(shù)中半徑R定義的位置順序。還可以將display()形參改為基類指針:7.1.8類型兼容voiddisplay(Pointp){p.ShowXY();}intmain(){PointP(1,1);//Point類對(duì)象

CircleCir(15,20,20);//Circle類對(duì)象

CylinderCY(15,300,300,50);//Cylinder類對(duì)象

display(P);//顯示對(duì)象P的中心坐標(biāo)

display(Cir);//顯示對(duì)象Cir的中心坐標(biāo)

display(CY);//顯示對(duì)象CY的中心坐標(biāo)

return0;}voiddisplay(Point&p){p.ShowXY();}如將上述程序改為:可將display()的參數(shù)改為引用形式:voiddisplay(Point*p){p->ShowXY();}

這樣,可以分別把基類對(duì)象P、派生類Circle的對(duì)象Cir和派生類Cylinder的對(duì)象CY的地址作為實(shí)參傳給基類類型指針,由C++編譯器實(shí)現(xiàn)隱式的類型轉(zhuǎn)換。根據(jù)C++類型兼容規(guī)則,p可以引用任何point的公有派生類對(duì)象。7.2多態(tài)性7.2.1多態(tài)性概述多態(tài)性(polymorphism)是面向?qū)ο蟪绦蛟O(shè)計(jì)的重要特性之一。多態(tài)是指同樣的消息被不同類型的對(duì)象接收時(shí)導(dǎo)致完全不同的行為。所謂消息是指對(duì)類的成員函數(shù)的調(diào)用,不同的行為是指不同的實(shí)現(xiàn),也就是調(diào)用了不同的函數(shù)。同一運(yùn)算符操縱不同類型的操作數(shù)就是多態(tài)性的一種體現(xiàn)。從實(shí)現(xiàn)的角度來看,多態(tài)可以劃分為兩類:編譯時(shí)的多態(tài)和運(yùn)行時(shí)的多態(tài)。前者是在編譯的過程中確定了同名操作的具體操作對(duì)象,而后者則是在程序運(yùn)行過程中才動(dòng)態(tài)地確定操作所針對(duì)的具體對(duì)象。這種確定操作的具體對(duì)象的過程就是聯(lián)編(binding),也稱為綁定。

§7-2多態(tài)性聯(lián)編可以在編譯和連接時(shí)進(jìn)行,稱為靜態(tài)聯(lián)編或先期聯(lián)編。在編譯、連接過程中,系統(tǒng)可以根據(jù)類型匹配等特征確定程序中操作調(diào)用與執(zhí)行該操作的代碼的關(guān)系,即確定某一個(gè)同名標(biāo)識(shí)到底是要調(diào)用哪一段程序代碼,函數(shù)的重載、函數(shù)模板的實(shí)例化均屬于靜態(tài)聯(lián)編。聯(lián)編也可以在運(yùn)行時(shí)進(jìn)行,稱為動(dòng)態(tài)聯(lián)編或滯后聯(lián)編。在編譯、連接過程中無法解決的聯(lián)編問題,要等到程序開始運(yùn)行之后再來確定。編譯時(shí)的多態(tài)性—函數(shù)重載;運(yùn)行時(shí)的多態(tài)性—虛函數(shù)。為實(shí)現(xiàn)某種功能而假設(shè)的虛擬函數(shù)簡(jiǎn)稱虛函數(shù)。

若語(yǔ)言不支持多態(tài),則不能稱面向?qū)ο蟮?,如VB。

7.2.2靜態(tài)聯(lián)編與動(dòng)態(tài)聯(lián)編調(diào)用重載函數(shù)時(shí),編譯器根據(jù)調(diào)用時(shí)參數(shù)的類型與個(gè)數(shù)在編譯時(shí)實(shí)現(xiàn)靜態(tài)聯(lián)編,將調(diào)用體與函數(shù)綁定。靜態(tài)聯(lián)編支持的多態(tài)性也稱為編譯時(shí)的多態(tài)性,或靜態(tài)多態(tài)性。

【例】演示靜態(tài)多態(tài)性123456789101112131415161718192021/*********************************************p9_6.cpp**演示靜態(tài)多態(tài)性*********************************************/#include<iostream>usingnamespacestd;classPoint{private: intX,Y;public:

Point(intX=0,intY=0) {

this->X=X,this->Y=Y; }

doublearea()//求面積

{ return0.0;}};constdoublePI=3.14159;7.2.2靜態(tài)聯(lián)編與動(dòng)態(tài)聯(lián)編222324252627282930313233343536373839404142434445464748classCircle:publicPoint{private: doubleradius;//半徑public:

Circle(intX,intY,doubleR):Point(X,Y) { radius=R; }

doublearea()//求面積

{ returnPI*radius*radius;}};intmain(){PointP1(10,10);cout<<"P1.area()="<<P1.area()<<endl;CircleC1(10,10,20);cout<<"C1.area()="<<C1.area()<<endl;Point*Pp;Pp=&C1;cout<<"Pp->area()="<<Pp->area()<<endl;Point&Rp=C1;cout<<"Rp.area()="<<Rp.area()<<endl;return0;}運(yùn)行結(jié)果:P1.area()=0

C1.area()=1256.64

Pp->area()=0

Rp.area()=07.2.2靜態(tài)聯(lián)編與動(dòng)態(tài)聯(lián)編程序解釋:程序39行調(diào)用P1.area()顯示了Point類對(duì)象P1的面積;程序41行通過調(diào)用C1.area()顯示了Circle類對(duì)象C1的面積;由于在類Circle中重新定義了area(),它覆蓋了基類的area(),故通過C1.area()調(diào)用的是類Circle中的area(),返回了正確結(jié)果。依照類的兼容性,程序43行用一個(gè)point型的指針指向了Circle類的對(duì)象C1,第44行通過Pp->area()調(diào)用area(),那么究竟調(diào)用的是哪個(gè)area(),C++此時(shí)實(shí)行靜態(tài)聯(lián)編,根據(jù)Pp的類型為Point型,將從Point類中繼承來的area()綁定給Pp,因此,此時(shí)調(diào)用的是Point派生的area(),顯示的結(jié)果為0。同樣,在第46行由引用Rp調(diào)用area()時(shí),也進(jìn)行靜態(tài)聯(lián)編,調(diào)用的是Point派生的area(),顯示的結(jié)果為0。顯然,靜態(tài)聯(lián)編盲目根據(jù)指針和引用的類型而不是根據(jù)實(shí)際指向的目標(biāo)確定調(diào)用的函數(shù),導(dǎo)致了錯(cuò)誤。動(dòng)態(tài)聯(lián)編則在程序運(yùn)行的過程中,根據(jù)指針與引用實(shí)際指向的目標(biāo)調(diào)用對(duì)應(yīng)的函數(shù),也就是在程序運(yùn)行時(shí)才決定如何動(dòng)作。虛函數(shù)(virtualfunction)允許函數(shù)調(diào)用與函數(shù)體之間的聯(lián)系在運(yùn)行時(shí)才建立,是實(shí)現(xiàn)動(dòng)態(tài)聯(lián)編的基礎(chǔ)。虛函數(shù)經(jīng)過派生之后,可以在類族中實(shí)現(xiàn)運(yùn)行時(shí)的多態(tài),充分體現(xiàn)了面向?qū)ο蟪绦蛟O(shè)計(jì)的動(dòng)態(tài)多態(tài)性。7.2.3虛函數(shù)的定義與使用虛函數(shù)定義的一般語(yǔ)法形式如下:virtual函數(shù)類型函數(shù)表(形參表)

{

函數(shù)體;}

其中:virtual關(guān)鍵字說明該成員函數(shù)為虛函數(shù)。在定義虛函數(shù)時(shí)要注意:p363

(1)

虛函數(shù)不能是靜態(tài)成員函數(shù),也不能是友元函數(shù)。因?yàn)殪o態(tài)成員函數(shù)和友元函數(shù)不屬于某個(gè)對(duì)象。

(2)

內(nèi)聯(lián)函數(shù)是不能在運(yùn)行中動(dòng)態(tài)確定其位置的,即使虛函數(shù)在類的內(nèi)部定義,編譯時(shí),仍將其看作非內(nèi)聯(lián)的。

(3)

只有類的成員函數(shù)才能說明為虛函數(shù),虛函數(shù)的聲明只能出現(xiàn)在類的定義中。因?yàn)樘摵瘮?shù)僅適用于有繼承關(guān)系的類對(duì)象,普通函數(shù)不能說明為虛函數(shù)。

(4)

構(gòu)造函數(shù)不能是虛函數(shù),析構(gòu)函數(shù)可以是虛函數(shù),而且通常聲明為虛函數(shù)。在正常情況下,對(duì)虛函數(shù)的訪問與其它成員函數(shù)完全一樣。只有通過指向基類的指針或引用來調(diào)用虛函數(shù)時(shí)才體現(xiàn)虛函數(shù)與一般函數(shù)的不同。使用虛函數(shù)是實(shí)現(xiàn)動(dòng)態(tài)聯(lián)編的基礎(chǔ)。要實(shí)現(xiàn)動(dòng)態(tài)聯(lián)編,概括起來需要滿足三個(gè)條件:

(1)

應(yīng)滿足類型兼容規(guī)則。

(2)

在基類中定義虛函數(shù),并且在派生類中要重新定義虛函數(shù)。

(3)

要由成員函數(shù)或者是通過指針、引用訪問虛函數(shù)。7.2.3虛函數(shù)的定義與使用一個(gè)類中將所有的成員函數(shù)都盡可能地設(shè)置為虛函數(shù)對(duì)編程固然方便,java語(yǔ)言中正是這樣做的,但是會(huì)增加一些時(shí)空上的開銷,對(duì)于C++來說,在對(duì)性能上有偏激追求的編程中,只選擇設(shè)置個(gè)別成員函數(shù)為虛函數(shù)。7.2.3虛函數(shù)的定義與使用【例】演示動(dòng)態(tài)多態(tài)性123456789101112131415161718192021222324252627282930/*********************************************p9_7.cpp**演示動(dòng)態(tài)多態(tài)性*********************************************/#include<iostream>usingnamespacestd;classPoint{private:intX,Y;public:

Point(intX=0,intY=0){this->X=X,this->Y=Y;}

virtualdoublearea()

//求面積如果基類的某個(gè)成員函數(shù)被說明為虛函數(shù),它無論被公有繼承多少次仍然保持其虛函數(shù)特性。

{return0.0;}};constdoublePI=3.14159;classCircle:publicPoint{private:doubleradius;//半徑public:

Circle(intX,intY,doubleR):Point(X,Y){ radius=R;}7.2.3虛函數(shù)的定義與使用313233343536373839404142434445464748doublearea()//求面積{returnPI*radius*radius;}};intmain(){PointP1(10,10);cout<<"P1.area()="<<P1.area()<<endl;CircleC1(10,10,20);cout<<"C1.area()="<<C1.area()<<endl;Point*Pp;Pp=&C1;cout<<"Pp->area()="<<Pp->area()<<endl;Point&Rp=C1;cout<<"Rp.area()="<<Rp.area()<<endl;return0;}運(yùn)行結(jié)果:P1.area()=0

C1.area()=1256.64

Pp->area()=1256.64

Rp.area()=1256.64

程序解釋:

程序16行在基類Point中,將area()聲明為虛函數(shù)。第39通過Point類對(duì)象P1調(diào)用虛函數(shù)area()。第41通過circle類對(duì)象C1調(diào)用area(),實(shí)現(xiàn)靜態(tài)聯(lián)編,調(diào)用的是Circle類area()。第44、46行分別通過Point類型指針與引用調(diào)用area(),由于area()為虛函數(shù),此時(shí)進(jìn)行動(dòng)態(tài)聯(lián)編,調(diào)用的是實(shí)際指向?qū)ο蟮腶rea()。7.2.3虛函數(shù)的定義與使用虛函數(shù)名為“虛”其實(shí)不虛:

①虛函數(shù)有函數(shù)體;

②虛函數(shù)在靜態(tài)聯(lián)編是當(dāng)成一般成員函數(shù)使用;③虛函數(shù)可以派生,如果在派生類中沒有重新定義虛函數(shù),虛函數(shù)就充當(dāng)了派生類的虛函數(shù)。

例①:將p9_7.cpp中Circle類的doublearea()改為:doublearea(inti){

returnPI*radius*radius;}

在Circle中,virtualdoublearea()被doublearea(inti)覆蓋,下面調(diào)用形式是錯(cuò)誤的:

CircleC1;

cout<<"C1.area()="<<C1.area()<<endl;Circle*Pp1=&C1;cout<<“Pp1->area()=”<<Pp1->area()<<endl;p360不恰當(dāng)?shù)奶摵瘮?shù)注意:當(dāng)在派生類中定義了虛函數(shù)的重載函數(shù),但并沒有重新定義虛函數(shù)時(shí),與虛函數(shù)同名的重載函數(shù)覆蓋了派生類中的虛函數(shù)。此時(shí)試圖通過派生類對(duì)象、指針、引用調(diào)用派生類的虛函數(shù)就會(huì)產(chǎn)生錯(cuò)誤。當(dāng)在派生類中未重新定義虛函數(shù),雖然虛函數(shù)被派生類繼承,但通過基類、派生類類型指針、引用調(diào)用虛函數(shù)時(shí),不實(shí)現(xiàn)動(dòng)態(tài)聯(lián)編,調(diào)用的是基類的虛函數(shù)。7.2.3虛函數(shù)的定義與使用例②:在p9_7.cpp的Circle類中加入:

doublearea(inti){ returnPI*radius*radius;}

程序運(yùn)行結(jié)果與p9_7.cpp結(jié)果相同。例③:在p9_7.cpp的Circle類中去掉函數(shù)doublearea(),程序運(yùn)行的結(jié)果如下:P1.area()=0C1.area()=0//調(diào)用了基類派生的virtualdoublearea()Pp->area()=0//調(diào)用了基類的virtualdoublearea()Rp.area()=0//調(diào)用了基類的virtualdoublearea()如果基類中的虛函數(shù)返回一個(gè)基類指針或返回一個(gè)基類的引用,子類中的虛函數(shù)返回一個(gè)子類的指針或子類的引用,則c++將其視為同名虛函數(shù)而進(jìn)行遲后聯(lián)編。p3627.2.3虛析構(gòu)函數(shù)

在C++中,不能定義虛構(gòu)造函數(shù),因?yàn)楫?dāng)開始調(diào)用構(gòu)造函數(shù)時(shí),對(duì)象還未完成實(shí)例化,只有在構(gòu)造完成后,對(duì)象才能成為一個(gè)類的名副其實(shí)的對(duì)象;但析構(gòu)函數(shù)可以是虛函數(shù),而且通常聲明為虛函數(shù),即虛析構(gòu)函數(shù)。

虛析構(gòu)函數(shù)定義形式如下:

virtual

~類名();當(dāng)基類的析構(gòu)函數(shù)被聲明為虛函數(shù),則派生類的析構(gòu)函數(shù),無論是否使用virtual關(guān)鍵字進(jìn)行聲明,都自動(dòng)成為虛函數(shù)。析構(gòu)函數(shù)聲明為虛函數(shù)后,程序運(yùn)行時(shí)采用動(dòng)態(tài)聯(lián)編,因此可以確保使用基類類型的指針就能夠自動(dòng)調(diào)用適當(dāng)?shù)奈鰳?gòu)函數(shù)對(duì)不同對(duì)象進(jìn)行清理工作。當(dāng)使用delete運(yùn)算符刪除一個(gè)對(duì)象時(shí),隱含著對(duì)析構(gòu)函數(shù)的一次調(diào)用,如果析構(gòu)函數(shù)為虛函數(shù),則這個(gè)調(diào)用采用動(dòng)態(tài)聯(lián)編,保證析構(gòu)函數(shù)被正確執(zhí)行?!纠坑锰撐鰳?gòu)函數(shù)刪除派生類動(dòng)態(tài)對(duì)象9.3.3虛析構(gòu)函數(shù)278910111213141516171819202122232425262728293031323334353637383940//**p9_8.cpp**classA{public:

virtual~A()//虛析構(gòu)函數(shù)

{cout<<"A::~A()iscalled."<<endl;}

A(){cout<<"A::A()iscalled."<<endl;}};classB:publicA//派生類{private:int*ip;public:

B(intsize=0){ ip=newint[size];cout<<"B::B()iscalled."<<endl;}

~B(){cout<<"B::~B()iscalled."<<endl;

delete[]ip;}};intmain(){A*b=newB(10);//類型兼容

deleteb;return0;}運(yùn)行結(jié)果:A::A()iscalled.

B::B()iscalled.

B::~B()iscalled.

A::~A()iscalled.程序解釋:

由于定義基類的析構(gòu)函數(shù)是虛析構(gòu)函數(shù),所以當(dāng)程序運(yùn)行結(jié)束時(shí),通過基類指針刪除派生類對(duì)象時(shí),先調(diào)用派生類析構(gòu)函數(shù),然后調(diào)用基類的析構(gòu)函數(shù)。如果基類的析構(gòu)函數(shù)不是虛析構(gòu)函數(shù),則程序運(yùn)行結(jié)果如下:A::A()iscalled.

B::B()iscalled.

A::~A()iscalled.§7-2多態(tài)性

7.2.4

類的分解p363

從相似的類中,將共有特征提取出來的過程稱為分解(factoring),分解使類的層

溫馨提示

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

最新文檔

評(píng)論

0/150

提交評(píng)論