




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
Chapter7-C++VirtualFunctionsandPolymorphismOutline
7.1 Introduction 7.2 TypeFieldsand
switch
Statements 7.3 VirtualFunctions 7.4 AbstractBaseClassesandConcreteClasses
7.5 Polymorphism
7.6 NewClassesandDynamicBinding
7.7 VirtualDestructors
7.8 CaseStudy:InheritingInterfaceandImplementation7.9 Polymorphism,
virtual
FunctionsandDynamic Binding“UndertheHood”8.0 VirtualBaseClassandAbstractBaseClasses
ObjectivesInthischapter,youwilllearn:Tounderstandthenotionofpolymorphism.Tounderstandhowtodefineandusevirtualfunctionstoeffectpolymorphism.Tounderstandthedistinctionbetweenabstractclassesandconcreteclasses.Tolearnhowtodefinepurevirtualfunctionstocreateabstractclasses.Toappreciatehowpolymorphismmakessystemsextensibleandmaintainable.TounderstandhowC++implementsvirtualfunctionsanddynamicbinding“underthehood.”7.1IntroductionvirtualfunctionsandpolymorphismDesignandimplementsystemsthataremoreeasilyextensibleProgramswrittentogenericallyprocessobjectsofallexistingclassesinahierarchy(更通用的)在C++中,多態(tài)性(面向?qū)ο蟮木瑁┩ㄟ^虛函數(shù)實(shí)現(xiàn)。在基類的函數(shù)前加上virtual關(guān)鍵字,在派生類中重寫該函數(shù),運(yùn)行時(shí)將會(huì)根據(jù)對(duì)象的實(shí)際類型來調(diào)用相應(yīng)的函數(shù):如果對(duì)象類型是派生類,調(diào)用派生類的函數(shù),如果對(duì)象類型是基類,調(diào)用基類的函數(shù)。多態(tài)性概述賦值兼容原則:派生類的對(duì)象可以被當(dāng)成基類的對(duì)象來使用。派生類的對(duì)象可以賦值給基類的對(duì)象Baseb;Derived;b=d;派生類的對(duì)象可以初始化基類對(duì)象的引用Derived;Base&b=d;派生類對(duì)象的地址可以賦值給基類的指針Derivedd;Base*bPtr=&d;原因分析:1)派生類是基類的超集,并包含有基類的成員(繼承來的)。2)當(dāng)將派生類的對(duì)象賦值給基類的對(duì)象時(shí),系統(tǒng)將繼承來的成員賦值給基類的對(duì)象;3)當(dāng)將基類的對(duì)象賦值給派生類的對(duì)象將導(dǎo)致派生類的對(duì)象有未被復(fù)制成員(成員不夠)。內(nèi)存布局:父類部分內(nèi)存子類繼承部分this指針子類對(duì)象的內(nèi)存weneedtodefineabehaviorforoneobjectaccordingtoitstype7.2TypeFieldsand
switch
Statements
7.2TypeFieldsand
switch
Statements
switchstatement
Takeanactiononanobjectbasedonitstype根據(jù)類型來判斷哪個(gè)行為被調(diào)用AswitchstructurecoulddeterminewhichfunctiontocallbasedonwhichtypeinahierarchyProblemswithswitchProgrammermayforgettotestallpossiblecasesinaswitch.Trackingthisdowncanbetimeconsuminganderrorpronevirtualfunctionsandpolymorphicprogrammingcaneliminatetheneedforswitch7.3VirtualFunctionsvirtualfunctionsUsedinsteadofswitchstatementsDefinition:Keyword
virtual
beforefunctionprototypeinbaseclass
virtualvoiddraw()const;Abase-classpointerorreferencetoaderivedclassobjectwillcallthecorrectdrawfunction(在運(yùn)行時(shí),依據(jù)對(duì)象的類型(由對(duì)象的地址決定)確認(rèn)調(diào)用哪一個(gè)draw函數(shù))Ifaderivedclassdoesnotdefinea
virtualfunctionitisinheritedfromthebaseclass如果一個(gè)派生類沒有定義virtual,就直接繼承基類的函數(shù)(virtual就跟普通函數(shù)一樣)7.3VirtualFunctionsForexampleShapePtr->Draw();(指針型調(diào)用)CompilerimplementsdynamicbindingFunctiondeterminedduringexecutiontime動(dòng)態(tài)綁定ShapeObject.Draw();CompilerimplementsstaticbindingFunctiondeterminedduringcompile-time靜態(tài)綁定If引用,滿足動(dòng)態(tài)綁定PureVirtualFunctions純虛函數(shù)是一種特殊的虛函數(shù),格式如下,在參數(shù)列表后加“=0”:virtual<類型><函數(shù)名>(<參數(shù)表>)=0;含有(或繼承)一個(gè)或多個(gè)純虛函數(shù)的類是抽象基類。除了作為抽象基類的派生類的對(duì)象的組成部分,不能創(chuàng)建抽象類型的對(duì)象。引入的原因:在很多情況下,基類本身生成對(duì)象是不合情理的。例如,動(dòng)物作為一個(gè)基類可以派生出老虎、孔雀等子類,但動(dòng)物本身生成對(duì)象明顯不合常理。7.4AbstractandConcreteClassesAbstractclasses抽象類Solepurposeistoprovideabaseclassforotherclasses抽象類純虛函數(shù):純粹是規(guī)范一個(gè)接口NoobjectsofanabstractbaseclasscanbeinstantiatedToogenerictodefinerealobjects,i.e.TwoDimensionalShapeCanhavepointersandreferences可以有指針和引用Concreteclasses-classesthatcaninstantiateobjects具體類Providespecificstomakerealobjects,i.e.Square,Circle提供具體來創(chuàng)建一個(gè)真實(shí)的對(duì)象
7.4AbstractandConcreteClassesMakingabstractclassesDefineoneormorevirtualfunctionsas“pure”byinitializingthefunctiontozero純虛函數(shù)
virtualdoubleearnings()const=0;Purevirtualfunction當(dāng)存在一個(gè)或者多個(gè)純虛函數(shù)的類就是抽象類7.4AbstractandConcreteClassesMakingabstractclassesDefineoneormorevirtualfunctionsas“pure”byinitializingthefunctiontozero純虛函數(shù)
virtualdoubleearnings()const=0;Purevirtualfunction除非在派生類中完全實(shí)現(xiàn)基類中所有的的純虛函數(shù),否則,派生類也變成了抽象類,不能實(shí)例化對(duì)象。抽象類(AbstractClass)解決了什么問題。抽象類是一種特殊的類,它是為了抽象和設(shè)計(jì)的目的而建立的,它處于繼承層次結(jié)構(gòu)的較上層。抽象類是不能定義對(duì)象的,在實(shí)際中為了強(qiáng)調(diào)一個(gè)類是抽象類,可將該類的構(gòu)造函數(shù)說明為保護(hù)的訪問控制權(quán)限。抽象類的主要作用是將有關(guān)的組織在一個(gè)繼承層次結(jié)構(gòu)中,由它來為它們提供一個(gè)公共的根,相關(guān)的子類是從這個(gè)根派生出來的。抽象類刻畫了一組子類的操作接口的通用語義,這些語義也傳給子類。一般而言,抽象類只描述這組子類共同的操作接口,而完整的實(shí)現(xiàn)留給子類。
抽象類只能作為基類來使用,其純虛函數(shù)的實(shí)現(xiàn)由派生類給出。如果派生類沒有重新定義純虛函數(shù),而派生類只是繼承基類的純虛函數(shù),則這個(gè)派生類仍然還是一個(gè)抽象類。如果派生類中給出了基類純虛函數(shù)的實(shí)現(xiàn),則該派生類就不再是抽象類了,它是一個(gè)可以建立對(duì)象的具體類了。
7.4AbstractandConcreteClasses7.5PolymorphismPolymorphism:Abilityforobjectsofdifferentclassestoresponddifferentlytothesamefunctioncall
不同類型不同的響應(yīng)Base-classpointer(orreference)callsa
virtual
functionC++choosesthecorrectoverriddenfunctioninobjectSupposeprint
notavirtualfunction
Employeee,*ePtr=&e; HourlyWorkerh,*hPtr=&h; ePtr->print();//callbase-classprintfunction
hPtr->print();//callderived-classprintfunction
ePtr=&h;//allowableimplicitconversion
ePtr->print();//stillcallsbase-classprint7.5PolymorphismPolymorphism:Supposeprintisavirtualfunction Employeee,*ePtr=&e; HourlyWorkerh,*hPtr=&h; ePtr->print();//callbase-classprintfunction
hPtr->print();//callderived-classprintfunction
ePtr=&h;//allowableimplicitconversion
ePtr->print();//callderived-classprint7.6NewClassesandDynamicBindingDynamicbinding(latebinding)Object'stypenotneededwhencompilingvirtualfunctionsForexample,wecancompilethefollowingcode.voidprintEmp(Employee&e) {//類型參數(shù)可以是Employee或其派生類 Employee*ePtr=&e; ePtr->print();//若print函數(shù)為虛函數(shù),則根據(jù)參數(shù)e的實(shí) //際類型來調(diào)用對(duì)應(yīng)的print}Accommodate(允許)newclassesthathavebeenaddedaftercompilationImportantforISV’s(IndependentSoftwareVendors)whodonotwishtorevealsourcecodetotheircustomers可以把具體實(shí)現(xiàn)算法的派生類封裝到加密的代碼庫中。7.6NewClassesandDynamicBinding派生類與虛函數(shù)派生類一般會(huì)重定義所繼承的虛函數(shù)。派生類沒有重定義某個(gè)虛函數(shù),則使用基類中定義的版本。派生類中虛函數(shù)的聲明必須與基類中的定義方式完全匹配,但有一個(gè)例外:返回對(duì)基類型的引用(或指針)的虛函數(shù)。派生類中的虛函數(shù)可以返回派生類的引用(或指針)。(?)例如:Employee類可以定義返回Employee*的虛函數(shù),如果這樣,HourlyWorker類中的虛函數(shù)重寫可以定義為返回Employee*或HourlyWorker*。7.7VirtualDestructorsProblem:Ifbase-classpointertoaderivedobjectis
deleted,thebase-classdestructorwillactontheobject注意析構(gòu)函數(shù)的調(diào)用Solution:Defineavirtualbase-classdestructorNow,theappropriatedestructorwillbecalled7.7VirtualDestructors刪除指向動(dòng)態(tài)分配對(duì)象的指針時(shí),需要運(yùn)行析構(gòu)函數(shù)在釋放對(duì)象的內(nèi)存之前清除對(duì)象。處理繼承層次中的對(duì)象時(shí),指針的靜態(tài)類型可能與被刪除對(duì)象的動(dòng)態(tài)類型不同——?jiǎng)h除實(shí)際指向派生類對(duì)象的基類類型指針。(?)7.7VirtualDestructors如果刪除基類指針,則需要運(yùn)行基類析構(gòu)函數(shù)并清除基類的成員,如果對(duì)象實(shí)際是派生類型的,則沒有定義該行為。要保證運(yùn)行適當(dāng)?shù)奈鰳?gòu)函數(shù),基類中的析構(gòu)函數(shù)必須為虛函數(shù):classEmployee{public:
//nowork,butvirtualdestructorneeded
//ifbasepointerthatpointstoaderivedobjectisever //deleted
virtual~Employee(){}};7.7VirtualDestructors如果析構(gòu)函數(shù)為虛函數(shù),那么通過指針調(diào)用時(shí),運(yùn)行哪個(gè)析構(gòu)函數(shù)將因指針?biāo)笇?duì)象類型的不同而不同:Employee*itemE=new
Employee();//samestaticanddynamictypedelete
itemE;//ok:destructorforEmployeecalleditemE=new
HourlyWorker();//ok:staticanddynamictypesdifferdelete
itemE;
//ok:destructorforHourlyWorkercalled7.7VirtualDestructors最佳實(shí)踐:即使析構(gòu)函數(shù)沒有工作要做,繼承層次的根類也應(yīng)該定義一個(gè)虛析構(gòu)函數(shù)。構(gòu)造函數(shù)和賦值操作符不是虛函數(shù)構(gòu)造函數(shù)是在對(duì)象完全構(gòu)造之前運(yùn)行的,在構(gòu)造函數(shù)運(yùn)行的時(shí)候,對(duì)象的動(dòng)態(tài)類型還不完整。每個(gè)類有自己的賦值操作符,派生類中的賦值操作符有一個(gè)與類本身類型相同的形參。將賦值操作符設(shè)為虛函數(shù)可能會(huì)出錯(cuò),因?yàn)樘摵瘮?shù)必須在基類和派生類中具有同樣的形參。7.8CaseStudy:InheritingInterfaceandImplementationRe-examinethePoint,Circle,CylinderhierarchyUsetheabstractbaseclassShapetoheadthehierarchy先抽象出通用接口,設(shè)計(jì)一個(gè)基類ShapeDefinition(abstractbaseclass)---------------------1.PointDefinition(derivedclass)1//Fig.7.1:shape.h2//DefinitionofabstractbaseclassShape抽象類3#ifndef
SHAPE_H4#define
SHAPE_H56classShape{7public:8
virtualdoublearea()const{return
0.0;}9
virtualdoublevolume()const{return
0.0;}1011
//purevirtualfunctionsoverriddeninderivedclasses12
virtualvoidprintShapeName()const=0;13
virtualvoidprint()const=0;14};//endclassShape15#endif1.
PointDefinition(derivedclass)1.1FunctionDefinitions18//DefinitionofclassPoint19#ifndef
POINT1_H20#define
POINT1_H2122#include<iostream>2324usingstd::cout;26#include
"shape.h"2728classPoint:publicShape{29public:30Point(int=0,int=0);//defaultconstructor31
voidsetPoint(int,int);32
intgetX()const{returnx;}33
intgetY()const{returny;}34
virtualvoidprintShapeName()const{cout<<"Point:";}35
virtualvoidprint()const;36private:37
intx,y;
//xandycoordinatesofPoint38};//endclassPoint39#endif
1.
PointDefinition(derivedclass)1.1FunctionDefinitions41//Fig.7.1:point1.cpp42//MemberfunctiondefinitionsforclassPoint43#include
"point1.h"4445Point::Point(inta,intb){setPoint(a,b);}4647voidPoint::setPoint(inta,intb)48{49x=a;50y=b;}//endfunctionsetPoint
53voidPoint::print()const
54{cout<<'['<<x<<
","<<y<<']';}1.CircleDefinition(derivedclass)56//DefinitionofclassCircle57#ifndef
CIRCLE1_H58#define
CIRCLE1_H59#include
"point1.h"6061classCircle:publicPoint{62public:63
//defaultconstructor64Circle(doubler=0.0,intx=0,inty=0);6566
voidsetRadius(double);67
doublegetRadius()const;68
virtualdoublearea()const;69
virtualvoidprintShapeName()const{cout<<"Circle:";}70
virtualvoidprint()const;71private:72
doubleradius;//radiusofCircle73};//endclassCircle7475#endif1.1FunctionDefinitions77//MemberfunctiondefinitionsforclassCircle#include<iostream>usingstd::cout;82#include
"circle1.h"8384Circle::Circle(doubler,inta,intb)85:Point(a,b)
//callbase-classconstructor86{setRadius(r);}8788voidCircle::setRadius(doubler){radius=r>0?r:0;}8990doubleCircle::getRadius()const{returnradius;}9192doubleCircle::area()const
93{return
3.14159*radius*radius;}9495voidCircle::print()const96{97Point::print();98cout<<";Radius="<<radius;99}//endfunctionprint1.CylinderDefinition(derivedclass)101//DefinitionofclassCylinder102#ifndef
CYLINDR1_H103#define
CYLINDR1_H104#include
"circle1.h"105106classCylinder:publicCircle{107public:108//defaultconstructor109Cylinder(doubleh=0.0,doubler=0.0,110
intx=0,inty=0);111112
voidsetHeight(double);113
doublegetHeight();114
virtual
doublearea()const;115
virtualdoublevolume()const;116
virtualvoidprintShapeName()const{cout<<"Cylinder:";}117
virtualvoidprint()const;118private:119
doubleheight;//heightofCylinder120};//endclassCylinder122#endif1.1FunctionDefinitions
123//Fig.7.1:cylindr1.cpp124//MemberandfriendfunctiondefinitionsforclassCylinder125#include<iostream>126127usingstd::cout;128129#include
"cylindr1.h"130131Cylinder::Cylinder(doubleh,doubler,intx,inty)132:Circle(r,x,y)
//callbase-classconstructor133{setHeight(h);}1341351.1FunctionDefinitions134135voidCylinder::setHeight(doubleh)136{height=h>0?h:0;}137138doubleCylinder::getHeight(){returnheight;}139140doubleCylinder::area()const141{142
//surfaceareaofCylinder143
return
2*Circle::area()+144
2*3.14159*getRadius()*height;145}//endfunctionarea146Driver1.Loadheaders1.1Functionprototypes
147doubleCylinder::volume()const
148{returnCircle::area()*height;}149150voidCylinder::print()const151{152Circle::print();153cout<<";Height="<<height;
}//endfunctionprint
Driver1.Loadheaders1.1Functionprototypes155//Fig.7.1:fig20_01.cpp156//Driverforshape,point,circle,cylinderhierarchy157#include<iostream>158159usingstd::cout;160usingstd::endl;161162#include<iomanip>163164usingstd::ios;165usingstd::setiosflags;166usingstd::setprecision;167168#include
"shape.h"169#include
"point1.h"170#include
"circle1.h"171#include
"cylindr1.h"1721.2Initializeobjects2.Functioncalls
173voidvirtualViaPointer(constShape*);174voidvirtualViaReference(constShape&);175176intmain()177{178cout<<setiosflags(ios::fixed|ios::showpoint)179<<setprecision(2);180181Pointpoint(7,11);//createaPoint182Circlecircle(3.5,22,8);//createaCircle183
Cylindercylinder(10,3.3,10,10);//createaCylinder184185point.printShapeName();//staticbinding186point.print();
//staticbinding187cout<<'\n';1881981.2Initializeobjects2.Functioncalls188189circle.printShapeName();//staticbinding190circle.print();//staticbinding191cout<<'\n';192193cylinder.printShapeName();//staticbinding194cylinder.print();//staticbinding195cout<<
"\n\n";196197Shape*arrayOfShapes[3];//arrayofbase-classpointers1982.Functioncalls
199
//aimarrayOfShapes[0]atderived-classPointobject200arrayOfShapes[0]=&point;201202
//aimarrayOfShapes[1]atderived-classCircleobject203arrayOfShapes[1]=&circle;204205
//aimarrayOfShapes[2]atderived-classCylinderobject206arrayOfShapes[2]=&cylinder;207208
//LoopthrougharrayOfShapesandcallvirtualViaPointer209
//toprinttheshapename,attributes,area,andvolume210
//ofeachobjectusingdynamicbinding.211cout<<"Virtualfunctioncallsmadeoff"212<<"base-classpointers\n“;2.Functioncalls213214
for(inti=0;i<3;i++)215virtualViaPointer(arrayOfShapes[i]);216217
//LoopthrougharrayOfShapesandcallvirtualViaReference218
//toprinttheshapename,attributes,area,andvolume219
//ofeachobjectusingdynamicbinding.220cout<<"Virtualfunctioncallsmadeoff"221<<"base-classreferences\n";2223.FunctionDefinitions223
for(intj=0;j<3;j++)224virtualViaReference(*arrayOfShapes[j]);225226
return
0;227}//endfunctionmain228229//Makevirtualfunctioncallsoffabase-classpointer230//usingdynamicbinding.
231voidvirtualViaPointer(constShape*baseClassPtr)
232{
233baseClassPtr->printShapeName();
234baseClassPtr->print();
235cout<<
"\nArea="<<baseClassPtr->area()236<<"\nVolume="<<baseClassPtr->volume()<<"\n\n";237}//endfunctionvirtualViaPointer
3.FunctionDefinitions238239//Makevirtualfunctioncallsoffabase-classreference240//usingdynamicbinding.241voidvirtualViaReference(constShape&baseClassRef)242{243baseClassRef.printShapeName();244baseClassRef.print();245cout<<"\nArea="<<baseClassRef.area()246<<"\nVolume="<<baseClassRef.volume()<<"\n\n";247}
//endfunctionvirtualViaReferenceProgramOutputPoint:[7,11]Circle:[22,8];Radius=3.50Cylinder:[10,10];Radius=3.30;Height=10.00
Virtualfunctioncallsmadeoffbase-classpointersPoint:[7,11]Area=0.00Volume=0.00
Circle:[22,8];Radius=3.50Area=38.48Volume=0.00
Cylinder:[10,10];Radius=3.30;Height=10.00Area=275.77Volume=342.12
Virtualfunctioncallsmadeoffbase-classreferencesPoint:[7,11]Area=0.00Volume=0.00
Circle:[22,8];Radius=3.50Area=38.48Volume=0.00
Cylinder:[10,10];Radius=3.30;Height=10.00Area=275.77Volume=342.12Override,OverloadandHideOverride(重寫),是指派生類重寫基類的虛函數(shù)。重寫的虛函數(shù)必須有一致的參數(shù)表和返回值(注意特殊情況)。Overload(重載),是指編寫一個(gè)與已有函數(shù)同名但是參數(shù)表不同的函數(shù)。例如一個(gè)函數(shù)即可以接受整型數(shù)作為參數(shù),也可以接受浮點(diǎn)數(shù)作為參數(shù)。
Hide(隱藏或遮蔽),是指派生類中的函數(shù)屏蔽了基類中相同名字的函數(shù)。遮蔽可以理解為特殊的覆蓋和特殊的重載,分為兩種情況:派生類的函數(shù)與基類的函數(shù)同名,但參數(shù)表不同。
(特殊的重載)派生類的函數(shù)與基類的函數(shù)同名且參數(shù)表相同,但沒有加上virtual關(guān)鍵字。
(特殊的重寫)7.9Polymorphism,
virtualFunctionsandDynamicBinding“UndertheHood”在面向?qū)ο蟮木幊讨?,首先?huì)針對(duì)數(shù)據(jù)進(jìn)行抽象(確定基類)和繼承(確定派生類),構(gòu)成類層次。這個(gè)類層次的使用者在使用它們的時(shí)候,如果仍然在需要基類的時(shí)候?qū)戓槍?duì)基類的代碼,在需要派生類的時(shí)候?qū)戓槍?duì)派生類的代碼,就等于類層次完全暴露在使用者面前。如果這個(gè)類層次有任何的改變(增加了新類),都需要使用者“知道”(針對(duì)新類寫代碼)。這樣就增加了類層次與其使用者之間的耦合。7.9Polymorphism,
virtualFunctionsandDynamicBinding“UndertheHood”多態(tài)可以使程序員脫離這種窘境。再回頭看看下面的例子感受一下。假設(shè)我們實(shí)現(xiàn)一個(gè)有100種動(dòng)物的動(dòng)物園系統(tǒng)。由于其中不同種類的動(dòng)物有著不同的eat和sleep行為,所以不能把eat和sleep提取出到基類Animal中。如何讓所有種類的動(dòng)物eat和sleep呢?不用多態(tài)不用多態(tài),函數(shù)調(diào)用只能在編譯時(shí)綁定。這就我們需要自己指定每一種動(dòng)物,然后調(diào)用它自己的eat和sleep函數(shù)??梢阅繙y(cè),這會(huì)嚴(yán)重降低效率,同時(shí)使工作變得異常枯燥。動(dòng)物們的吃飯的代碼如下:
dog.eat(); donkey.eat(); chichen.eat();parrot.eat();horse.eat();monkey.eat();donkey.eat();mule.eat();pig.eat();cow.eat();deer.eat();ox.eat();goat.eat();lion.eat();tiger.eat();fox.eat();wolf.eat();bear.eat();…
動(dòng)物們的睡覺的代碼如下:
dog.sleep(); donkey.sleep(); chichen.sleep();parrot.sleep();horse.sleep();monkey.sleep();donkey.sleep();mule.sleep();pig.sleep();cow.sleep();deer.sleep();ox.sleep();goat.sleep();lion.sleep();tiger.sleep();fox.sleep();wolf.sleep();bear.sleep();…
創(chuàng)建對(duì)象的代碼如下:
Dogdog; Donkeydonkey; Chichenchichen;Parrotparrot;Horsehorse;Monkeymonkey;Donkeydonkey;Mulemule;Pigpig;Cowcow;Deerdeer;Oxox;Goatgoat;Lionlion;Tigertiger;Foxfox;Wolfwolf;Bearbear;…
使用多態(tài)創(chuàng)建對(duì)象的代碼如下:
Animal*ptr[100];ptr[0]=newDog; ptr[1]=newDonkey;ptr[2]=newChichen;ptr[3]=newParrot;…ptr[98]=newHorse;ptr[99]=newMule;動(dòng)物們的吃飯的代碼如下:
for(inti=0;i<100;i++){ptr[i]->eat();}動(dòng)物們睡覺的代碼如下:for(inti=0;i<100;i++){ptr[i]->sleep();}這完全歸功于多態(tài)--編譯器針對(duì)虛函數(shù)產(chǎn)生了可以在運(yùn)行時(shí)刻確定被調(diào)用函數(shù)的代碼。7.9Polymorphism,
virtualFunctionsandDynamicBinding“UndertheHood”WhentousePolymorphism在你設(shè)計(jì)一個(gè)基類的時(shí)候,如果發(fā)現(xiàn)一個(gè)函數(shù)需要在派生類里有不同的表現(xiàn),那么它就應(yīng)該是虛的。從設(shè)計(jì)的角度講,出現(xiàn)在基類中的虛函數(shù)是接口,出現(xiàn)在派生類中的虛函數(shù)是接口的具體實(shí)現(xiàn)。通過這樣的方法,就可以將對(duì)象的行為抽象化。7.9Polymorphism,
virtualFunctionsandDynamicBinding“UndertheHood”Compile-timeBinding(編譯期綁定,alsocalledStaticBinding)和Run-timeBinding(運(yùn)行期綁定,alsocalledDynamicBinding)。Binding(綁定):決定執(zhí)行哪一段代碼。
voidsayHi(){ cout<<“Hello!”<<endl;}
intmain(){ sayHi();
return0;}將sayHi的調(diào)用綁定到sayHi的實(shí)現(xiàn)處:編譯器將所有對(duì)sayHi的調(diào)用視為執(zhí)行代碼:
cout<<“Hello!”<<endl;C++編譯期綁定和運(yùn)行期綁定一個(gè)函數(shù)的名稱對(duì)應(yīng)了該函數(shù)在內(nèi)存中的起始地址,常稱作該函數(shù)的入口地址。編譯期綁定:執(zhí)行哪一段代碼由編譯器在編譯階段決定;即函數(shù)的入口地址在編譯時(shí)確定。運(yùn)行期綁定:執(zhí)行哪一段代碼是在運(yùn)行階段決定;即函數(shù)的入口地址在運(yùn)行時(shí)確定。1 classBase{2public:3 voidf(){cout<<“Base::f()”<<endl;}4};5
classDerive:publicBase{6
public:7
voidf(){cout<<“Derive::f()”<<endl;}9 };10
int
main(){
Base*ptr=NULL;
ptr=newDerive;
ptr->f(); deleteptr; return0;
}
Base::f()Output編譯期綁定:在編譯時(shí),根據(jù)ptr的數(shù)據(jù)類型Base*進(jìn)行綁定,即綁定到Base::f()。編譯期綁定和運(yùn)行期綁定的區(qū)別1 classBase{2public:3 virtualvoidf(){cout<<“Base::f()”<<endl;}4};5
classDerive:publicBase{6
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年鋁合金內(nèi)懸浮抱桿(管式)項(xiàng)目可行性研究報(bào)告
- 2025年車輛軸承磁粉探傷機(jī)項(xiàng)目可行性研究報(bào)告
- 2025年自動(dòng)調(diào)整切斷剝皮鉗項(xiàng)目可行性研究報(bào)告
- 理財(cái)培訓(xùn)行業(yè)發(fā)展?jié)摿Ψ治黾巴顿Y戰(zhàn)略咨詢報(bào)告
- 中國(guó)彩色感光材料市場(chǎng)規(guī)模預(yù)測(cè)及投資戰(zhàn)略咨詢報(bào)告
- 搭船的鳥第二課時(shí)教學(xué)設(shè)計(jì)-2024-2025學(xué)年統(tǒng)編版語文三年級(jí)上冊(cè)
- 百分?jǐn)?shù)與小數(shù)的互化(教學(xué)設(shè)計(jì))-2024-2025學(xué)年數(shù)學(xué)六年級(jí)上冊(cè)蘇教版
- 2025年注射用輔酶項(xiàng)目可行性研究報(bào)告
- 2025年戶外線插座項(xiàng)目可行性研究報(bào)告
- Unit 1 Teenage Life Reading and Thinking 教學(xué)設(shè)計(jì)2024-2025學(xué)年高中英語人教版(2019)必修第一冊(cè)
- 國(guó)有企業(yè)管理人員處分條例(2024)課件
- 部編六年級(jí)下冊(cè)語文《1 北京的春節(jié)》課件
- (正式版)JB∕T 14732-2024 中碳和中碳合金鋼滾珠絲杠熱處理技術(shù)要求
- 2024年食堂經(jīng)理年終總結(jié)5篇
- 第22課 現(xiàn)代科技革命和產(chǎn)業(yè)發(fā)展(課件)-【中職專用】《世界歷史》(高教版2023基礎(chǔ)模塊)
- 2024年南京科技職業(yè)學(xué)院?jiǎn)握新殬I(yè)適應(yīng)性測(cè)試題庫完整
- 家長(zhǎng)會(huì)課件:小學(xué)三年級(jí)家長(zhǎng)會(huì) 課件
- 醫(yī)院專業(yè)技術(shù)年度考核總結(jié)報(bào)告
- 2024中考道法時(shí)政熱點(diǎn)《中國(guó)外交大事大盤點(diǎn)》課件
- 小學(xué)生國(guó)家文化安全教育
- 2024年消防初級(jí)考試模擬試題和答案
評(píng)論
0/150
提交評(píng)論