继承和多态应用和示例闫哲yzh@cs.pku.edu.cn2005年6月24日内容继承的内存布局赋值相容规则继承举例虚函数实现原理多态性举例设计模式继承的内存布局通过继承,派生类中包含基类成员classPoint2d{public:Point2d(){//…}//……protected:floatx,y;};classPoint3d:publicPoint2d{public:Point3d():Point2d(){//…}//……private:floatz;};Point3dobj2;Point2dobj1;floatxfloatyfloatzfloatxfloaty基类成员private:构造函数和析构函数的调用顺序访问权限的理解继承的内存布局对比:对象成员classPoint2d{public:Point2d(){//…}//……protected:floatx,y;};classPoint3d:{public:Point3d():point(){//…}//……private:Point2dpoint;floatz;};Point3dobj2;Point2dobj1;floatxfloatyfloatzfloatxfloatypoint对象成员赋值相同规则通过公有继承,派生类的对象可以当作基类使用classPoint2d{public:voidshow();protected:floatx,y;};classPoint3d:publicPoint2d{public:voidshow();private:floatz;};voidmain(){Point2dobj2d;Point3dobj3d;obj2d=obj3d;//对象赋值obj2d.show();//调用Point2d::show()}Point3dobj3d;Point2dobj2d;floatxfloatyfloatzfloatxfloaty派生类对象赋值给基类对象向上映射、对象切片赋值相同规则通过公有继承,派生类指针可以赋给基类指针classPoint2d{public:voidshow();protected:floatx,y;};classPoint3d:publicPoint2d{public:voidshow();private:floatz;};voidmain(){Point2dobj2d;Point3dobj3d;Point3dobj3d;Point2dobj2d;p3dp2dfloatxfloatyfloatzfloatxfloatyp2d//指针赋值Point2d*p2d=&obj2d;Point3d*p3d=&obj3d;p2d=p3d;p2d-show();调用Point2d::show()}多重继承的内存布局通过多重继承,派生类中包含各基类成员classPoint2d{public://…protected:floatx,y;};classPoint3d:publicPoint2d{public://…protected:floatz;};classVertex{public://…protected:Vertex*next;};classVertex3d:publicPoint3d,publicVertex{public://…protected:floatmumble;};Point2dPoint3dVertex3dVertex多重继承的内存布局floatxfloatyfloatzVertex*nextfloatxfloatyfloatzPoint2d子对象Point3d子对象Point2d子对象Vertex子对象Point3dobj1;floatmumbleVertex*nextVertex3dobj3;Vertexobj2;//对象赋值obj1=obj3;obj2=obj3;//指针赋值Point3d*p3d=&obj3;Vertex*pv=&obj3;//涉及指针偏移赋值相容规则:多重继承的内存布局多重继承中数据成员的二义性intmemberintmemberinttotal来自base1classbase1{protected:intmember;public:base1(){//…}};classbase2{protected:intmember;public:base2(){//…}};classderived:publicbase1,publicbase2{private:inttotal;public:derived(){//…}voidfunc(){member=0;//二义性}};来自base2derived对象布局base1::member=0;base2::member=0;多重继承的内存布局虚拟基类之前的内存布局intbintb2classbase{protected:intb;};classbase1:publicbase{protected:intb1;};classbase2:publicbase{protected:intb2;};classderived:publicbase1,publicbase2{floatd;public:intfun();};intbintb1base2的内存布局base1的内存布局intbintb1intbintb2floatd二义性derived的内存布局不能把derived对象当base对象使用多重继承的内存布局通过指针指向共享的虚拟基类虚拟基类的内存布局intb2intbclassbase{protected:intb;};classbase1:virtualpublicbase{protected:intb1;};classbase2:virtualpublicbase{protected:intb2;};classderived:publicbase1,publicbase2{floatd;public:intfun();};intb1intbbase*pbase*pbase1的内存布局base2的内存布局intb1intb2floatdintbbase*pbase*pderived的内存布局可以把derived对象当base对象使用继承的使用从现实中捕获一般-特殊关系classAutomobile{public:Automobile();voidstart();voidstop();voidspeedup();voidspeeddown();protected:char*brand;floatprice;floatspeed;};classCar:publicAutomobile{public:Car();voidabsstop();private:floatgas_comsume;};classJeep:publicAutomobile{public:Jeep();voidclimb();private:intdrive;};classTruck:publicAutomobile{public:Truck();voidtransport();private:floatload;};AutomobileCarJeepTruck继承的使用从相似的类中提取共同的特征,形成类层次在银行业务中,有储蓄(Saving)账户和结算(Checking)账户之分,两个类的设计:SavingaccNumberbalanceSaving()Withdraw()Deposit()Display()CheckingaccNumberbalanceremittanceChecking()Withdraw()Deposit()Display()SetRemit()Consume()储蓄账户结算账户继承的使用//类的定义省略#includeiostream.hSaving::Saving(intaccNo,floatbal=0){accNumber=accNo;balance=bal;}voidSaving::Withdraw(floatbal){if(balbalance&&bal0)balance-=bal;}voidSaving::Deposit(floatbal){if(bal0)balance+=bal;}voidSaving::Display(){cout“SavingAccount[”accNo“]:”balanceendl;}Checking::Checking(intaccNo,floatbal=0){accNumber=accNo;balance=bal;}voidChecking::Withdraw(floatbal){floattmp;//…根据remit值计算tmpif(tmpbalance&&tmp0)balance-=tmp;}voidChecking::Deposit(floatbal){if(bal0)balance+=bal;}voidChecking::Display(){cout“SavingAccount[”accNo“]:”balanceendl;}voidChecking::SetRemit(intrem){remittance=rem;}voidChecking::Consume(floatprice,floatadd=0){floattmp=price+add;if(tmpbalance&&tmp0)balance-=tmp;}继承的使用Checking类继承Saving类SavingaccNumberbalanceSaving()Withdraw()Deposit()Display()CheckingremittanceChecking()Withdraw()SetRemit()Consume()储蓄账户结算账户继承的使用classSaving{protected:intaccNumber;floatbalance;public:Saving(intaccNo,floatbal=0);voidWithdraw(floatbal);voidDeposit(floatbal);voidDisplay();};classChecking:publicSaving{private:intremittance;public:Checking(intaccNo,floatbal=0);voidWithdraw(floatbal);voidsetRemit(intrem);voidConsume(floatprice,floatadd);};#includeiostream.h//Saving的实现…Checking::Checking(intaccNo,floatbal=0):Saving(accNo,bal){}voidChecking::Withdraw(floatbal){floattmp;//根据remit计算if(tmpbalance&&tmp0)balance-=tmp;}voidChecking::setRemit(intrem){remittance=remit;}VoidChecking::Consume(floatprice,floatadd=0){floattmp=price+add;if(tmpbalance&&tmp0)balance-=tmp;}继承的使用思考继承关系:结算帐户is-a储蓄帐户吗?SavingChecking增加数据成员overdraft表示透支范围在Withdraw()中允许透支则Checking也得到了该数据成员其实,Checking不是一种Saving,而是不同类型的两种帐户AccountaccNumberbalanceAccount()Withdraw()Deposit()Display()SavingoverdraftSaving()Withdraw()Checki