《C面向对象程序设计教程.pptx》由会员分享,可在线阅读,更多相关《C面向对象程序设计教程.pptx(56页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、1继承性是面向对象程序设计中最重要的机制。这种继承性是面向对象程序设计中最重要的机制。这种机制机制提供了无限重复利用程序资源的一种途径提供了无限重复利用程序资源的一种途径。通过通过C+语言中的继承机制,语言中的继承机制,可以扩充和完善旧的可以扩充和完善旧的程序设计以适应新的需求。程序设计以适应新的需求。这样不仅可以节省程序开发的时间和资源,并且为这样不仅可以节省程序开发的时间和资源,并且为未来程序增添了新的资源。未来程序增添了新的资源。5.1 派生和继承的相关概念和作用第1页/共56页2classStudentintnum;charname30;charsex;public:voiddispl
2、ay()/对成员函数对成员函数display的定义的定义coutnum:numendl;coutname:nameendl;coutsex:sexendl;5.1 派生和继承的相关概念和作用第2页/共56页3classStudend1intnum;/此行原来己有此行原来己有charname20;/此行原来己有此行原来己有charsex;/此行原来己有此行原来己有intage;charaddr20;public:voiddisplay();/此行原来己有此行原来己有coutnum:numendl;/此行原来己有此行原来己有coutname:nameendl;/此行原来己有此行原来己有coutse
3、x:sexendl;/此行原来己有此行原来己有coutage:ageendl;coutaddress:addrendl;5.1 派生和继承的相关概念和作用第3页/共56页4利用原来定义的类利用原来定义的类StudentStudent作为基础,再加上新的作为基础,再加上新的内容即可,以减少重复的工作量。内容即可,以减少重复的工作量。C+C+提供的继提供的继承机制就是为了解决这个问题。承机制就是为了解决这个问题。在在C+中所谓中所谓“继承继承”就是在一个已存在的类的基就是在一个已存在的类的基础上建立一个新的类。础上建立一个新的类。已存在的类称为已存在的类称为“基类基类(baseclass)”或或“
4、父类父类(fatherclass)”。新建立的类称为新建立的类称为“派生类派生类(derivedclass)”或或“子类子类(sonclass)”。5.1 派生和继承的相关概念和作用第4页/共56页5classStudent1:publicStudent/声明基类是声明基类是Studentprivate:intage;/新增加的数据成员新增加的数据成员stringaddr;/新增加的数据成员新增加的数据成员public:voiddisplay_1()/新增加的成员函数新增加的成员函数coutage:ageendl;coutaddress:addrendl;5.1 派生和继承的相关概念和作用第5
5、页/共56页6类类A派生类派生类B:类:类A为基类,类为基类,类B为派生类。为派生类。AB新增加的成员数新增加的成员数据和成员函数据和成员函数5.1 派生和继承的相关概念和作用第6页/共56页7在在C+语言中,语言中,一个派生类可以从一个基类派生,一个派生类可以从一个基类派生,也可以从多个基类派生。也可以从多个基类派生。从一个基类派生的继承称为单继承;从一个基类派生的继承称为单继承;从二个或多个基类派生的继承称为多重继承。从二个或多个基类派生的继承称为多重继承。通过继承机制,可以利用已有的数据类型来定义新通过继承机制,可以利用已有的数据类型来定义新的数据类型。的数据类型。所定义的新的数据类型不
6、仅拥有新定所定义的新的数据类型不仅拥有新定义的成员,而且还同时拥有旧的成员。义的成员,而且还同时拥有旧的成员。5.1 派生和继承的相关概念和作用第7页/共56页8在建立派生类的过程中,基类不会做任何改变;在建立派生类的过程中,基类不会做任何改变;派生类则除了继承基类的所有可引用的成员变量派生类则除了继承基类的所有可引用的成员变量和成员函数外,还可另外定义本身的成员变量和和成员函数外,还可另外定义本身的成员变量和处理这些变量的函数处理这些变量的函数由于派生类可继承基类的成员变量和成员函数,由于派生类可继承基类的成员变量和成员函数,因此在基类中定义好的数据和函数等的程序代码因此在基类中定义好的数据
7、和函数等的程序代码可重复使用,这样可以提高程序的可靠性。可重复使用,这样可以提高程序的可靠性。5.1 派生和继承的相关概念和作用第8页/共56页9当当从从已已有有的的类类中中派派生生出出新新的的类类时时,可可以以对对派派生生类类做做以下几种变化:以下几种变化:1、可以继承基类的成员数据或成员函数。可以继承基类的成员数据或成员函数。2、可以增加新的成员变量。、可以增加新的成员变量。3、可以增加新的成员函数。、可以增加新的成员函数。4、可以重新定义已有的成员函数。、可以重新定义已有的成员函数。5、可以改变现有的成员属性。、可以改变现有的成员属性。5.1 派生和继承的相关概念和作用第9页/共56页1
8、0类类A派生类派生类B:类:类A为基类,类为基类,类B为派生类。为派生类。AB但派生并不是简单的扩充,有可能改变派生类中的基类的但派生并不是简单的扩充,有可能改变派生类中的基类的成员性质。成员性质。有三种派生方式:公有派生、保护派生、私有派生。有三种派生方式:公有派生、保护派生、私有派生。默认的是私有派生。默认的是私有派生。classB:publicA.;classB:protectedA.;classB:privateA.;classB:A.;A为私有派生5.2 三种继承的派生类的成员访问方式第10页/共56页11从一个基类派生一个类的一般格式为:从一个基类派生一个类的一般格式为:class
9、ClassName:BaseClassNameprivate:.;/私有成员说明私有成员说明public:.;/公有成员说明公有成员说明protected:.;/保护成员说明保护成员说明派生类名基类名继承方式public:表示公有基类表示公有基类private:表示私有基类表示私有基类(默认默认)protected:表示保护基类表示保护基类派生类中新增加的成员派生类中新增加的成员5.2 三种继承的派生类的成员访问方式第11页/共56页12公有派生class ClassName:public BaseClassName公公有有派派生生时时,基基类类中中所所有有成成员员在在派派生生类类中中保保持持
10、各各个个成成员员的访问权限的访问权限。公有派生,派生类中保持基类的成员特性基类成员属性基类成员属性派生类中派生类中派生类外派生类外公有公有可以引用可以引用可以引用可以引用保护保护可以引用可以引用不可引用不可引用私有私有不可引用不可引用不可引用不可引用5.2 三种继承的派生类的成员访问方式第12页/共56页13x(私有私有)y(保护保护)z(公有公有)Getx()Gety()ShowA()Ax(私私有私私有)y(保护保护)z(公有公有)Getx()Gety()ShowA()Bm(私有私有)n(私有私有)B()Show()Sum()publicx在类在类B新增成员中不能直接调用新增成员中不能直接调
11、用y在类在类B中可以调用中可以调用z在整个文件中可以调用在整个文件中可以调用对类对类B的对象初始化即是对的对象初始化即是对x,y,z,m,n等全部成员的初始化等全部成员的初始化5.2 三种继承的派生类的成员访问方式第13页/共56页14classAintx;protected:inty;public:intz;A(inta,intb,intc)x=a;y=b;z=c;/基类初始化基类初始化intGetx()returnx;/返回返回xintGety()returny;/返回返回yvoidShowA()coutx=xty=ytz=zn;classB:publicAintm,n;public:B(
12、inta,intb,intc,intd,inte):A(a,b,c)m=d;n=e;voidShow()cout“m=mt“n=nn;coutx=Getx()ty=ytz=zn;intSum()return(Getx()+y+z+m+n);voidmain()Bb1(1,2,3,4,5);b1.ShowA();b1.Show();coutSum=b1.Sum()n;coutx=b1.Getx()t;couty=b1.Gety()t;coutz=b1.zn;公有派生对基类初始化因为x是基类私有,所以在派生类和类外中不能直接引用因为y是基类保护,所以在派生类中可以直接引用。而在类外不可直接引用。因
13、为z是基类公有,所以在派生类中和类外均可直接引用。5.2 三种继承的派生类的成员访问方式仅对派生类中的新增成员进行初始化第14页/共56页15私有派生class ClassName:private BaseClassName此此时时,基基类类中中公公有有成成员员和和保保护护成成员员在在派派生生类类中中均均变变为为私私有有,在在派派生生类类中中仍可直接使用这些成员,仍可直接使用这些成员,基类中的私有成员,在派生类中不可直接使用。基类中的私有成员,在派生类中不可直接使用。基类成员属性基类成员属性派生类派生类派生类外派生类外公有公有可以引用可以引用不可引用不可引用保护保护可以引用可以引用不可引用不可
14、引用私有私有不可引用不可引用不可引用不可引用基类:基类:public:(变为私有变为私有)在派生类中使用,类外不可使用在派生类中使用,类外不可使用protected:(变为私有)在派生类中使用,类外不可使用变为私有)在派生类中使用,类外不可使用private:不能在派生类中和类外使用不能在派生类中和类外使用5.2 三种继承的派生类的成员访问方式第15页/共56页16x(私有私有)y(保护保护)z(公有公有)Getx()Gety()ShowA()Ax(私私有私私有)y(私有私有)z(私有私有)Getx()Gety()ShowA()Bm(私有私有)n(私有私有)B()Show()Sum()priv
15、atex在类在类B新增加的成员中新增加的成员中不能直接调用不能直接调用y在类在类B中可以调用中可以调用z在类在类B中可以调用中可以调用对类对类B的对象初始化即是对的对象初始化即是对x,y,z,m,n等全部成员的初始化等全部成员的初始化均为私均为私有类有类B外不能外不能引用引用5.2 三种继承的派生类的成员访问方式第16页/共56页17classAintx;protected:inty;public:intz;A(inta,intb,intc)x=a;y=b;z=c;/基类初始化基类初始化intGetx()returnx;/返回返回xintGety()returny;/返回返回yvoidShow
16、A()coutx=xty=ytz=zn;classB:privateAintm,n;public:B(inta,intb,intc,intd,inte):A(a,b,c)m=d;n=e;voidShow()cout“m=mt“n=nn;coutx=Getx()ty=ytz=zn;intSum()return(Getx()+y+z+m+n);voidmain(void)Bb1(1,2,3,4,5);b1.ShowA();b1.Show();coutSum=b1.Sum()n;coutx=b1.Getx()t;couty=b1.Gety()t;coutz=b1.zn;私有派生对基类初始化因为x是基
17、类私有,所以在派生类和类外中不能直接引用y是基类保护,所以在派生类中可以直接引用。而在类外不可直接引用。z是基类公有,私有派生变为私有,所以在派生类中可直接引用,而在类外不可。这些函数都是基类公有,在类外不可使用。Aa1(1,2,3);a1.ShowA();第17页/共56页18保护派生class ClassName:protected BaseClassName此此时时,基基类类中中公公有有和和保保护护成成员员在在派派生生类类中中均均变变为为保保护护的的,在在派派生生类类中中仍仍可直接使用这些成员,可直接使用这些成员,基类中的私有成员,在派生类中不可直接使用。基类中的私有成员,在派生类中不可
18、直接使用。基类成员属性基类成员属性派生类派生类派生类外派生类外公有公有可以引用可以引用不可引用不可引用保护保护可以引用可以引用不可引用不可引用私有私有不可引用不可引用不可引用不可引用基类:基类:public:(变为保护变为保护)在派生类中使用,类外不可使用在派生类中使用,类外不可使用protected:(仍为保护)在派生类中使用,类外不可使用仍为保护)在派生类中使用,类外不可使用private:不能在派生类中和类外使用不能在派生类中和类外使用5.2 三种继承的派生类的成员访问方式第18页/共56页19x(私有私有)y(保护保护)z(公有公有)Getx()Gety()ShowA()Ax(私私有私
19、私有)y(保护保护)z(保护保护)Getx()Gety()ShowA()Bm(私有私有)n(私有私有)B()Show()Sum()protectedx在类在类B新增加的成员中不新增加的成员中不能直接调用能直接调用y在类在类B中可以调用中可以调用z在类在类B中可以调用中可以调用对类对类B的对象初始化即是对的对象初始化即是对x,y,z,m,n等全部成员的初始化等全部成员的初始化均为保护均为保护类类B外不外不能引用能引用5.2 三种继承的派生类的成员访问方式第19页/共56页20protected成员是一种具有血缘关系内外有别的成成员是一种具有血缘关系内外有别的成员。员。它对派生类的对象而言,是公开
20、成员,可以访问,它对派生类的对象而言,是公开成员,可以访问,对对血缘外部而言,与私有成员一样被隐蔽血缘外部而言,与私有成员一样被隐蔽。5.2 三种继承的派生类的成员访问方式第20页/共56页21当定义了一个类,当定义了一个类,这个类这个类只能用作基类只能用作基类来派生出来派生出新的类,而不能用这种类来定义对象时,称这种新的类,而不能用这种类来定义对象时,称这种类为抽象类。类为抽象类。当对某些特殊的对象要进行很好地封装时,需要当对某些特殊的对象要进行很好地封装时,需要定义抽象类。定义抽象类。将类的构造函数或析构函数的访问权限定义为将类的构造函数或析构函数的访问权限定义为保保护护的时,这种类为的时
21、,这种类为抽象类抽象类。5.3 抽象类与保护的成员函数第21页/共56页22当把类中的构造函数或析构函数说明为当把类中的构造函数或析构函数说明为私有私有的时,的时,所定义的类通常是没有任何实用意义的,一般情况所定义的类通常是没有任何实用意义的,一般情况下,不能用它来产生对象,也不能用它来产生派生下,不能用它来产生对象,也不能用它来产生派生类。类。5.3 抽象类与保护的成员函数第22页/共56页23x(私有私有)y(私有私有)A()(保护保护)ShowA()(公有公有)Ax(私私有私私有)y(私私有私私有)A()(保护保护)ShowA()Bm(私有私有)B()Show()public在类在类B中
22、不能定义中不能定义A的对象的对象在任何时候都不能定义在任何时候都不能定义A的对象的对象但可以在初始化类但可以在初始化类B的对象时初始化的对象时初始化原类原类A中的成员中的成员,因为,因为A()在类在类B中是可以被调用的。中是可以被调用的。5.3 抽象类与保护的成员函数第23页/共56页24classAintx,y;protected:A(inta,intb)x=a;y=b;/基类初始化基类初始化public:voidShowA()coutx=xty=yn;classB:publicAintm;Aa1;/在派生类中也不可以定义在派生类中也不可以定义A的对象,实际上还是类外调用的对象,实际上还是类
23、外调用public:B(inta,intb,intc):A(a,b)/可以在派生类中调用可以在派生类中调用A的构造函数的构造函数m=c;voidShow()cout“m=mn;ShowA();voidmain()Bb1(1,2,3);/可以定义派生类对象可以定义派生类对象b1.Show();Aaa;/不可定义不可定义A的对象的对象a1(4,5)5.3 抽象类与保护的成员函数第24页/共56页25可以用多个基类来派生一个类。可以用多个基类来派生一个类。ABCD多重继承是单多重继承是单一继承的扩展一继承的扩展派生类中新定义的成员5.4 多重继承第25页/共56页26格式为:格式为:class类名类
24、名:类名类名1,.,类名类名nprivate:.;/私有成员说明私有成员说明;public:.;/公有成员说明公有成员说明;protected:.;/保护的成员说明保护的成员说明;继承方式classD:publicA,protectedB,privateC./派生类中新增加成员派生类中新增加成员;5.4 多重继承第26页/共56页27classA intx1,y1;public:A(inta,intb)x1=a;y1=b;voidShowA(void)coutA.x=x1tA.y=y1endl;classBintx2,y2;public:B(inta,intb)x2=a;y2=b;voidSh
25、owB()coutB.x=x2tB.y=y2endl;classC:publicA,privateBintx,y;public:C(inta,intb,intc,intd,inte,intf):A(a,b),B(c,d)x=e;y=f;voidShowC()coutC.x=xtC.y=yendl;ShowA();ShowB();voidmain()Cc(1,2,3,4,5,6);c.ShowC();c.ShowA();c.ShowB();公有派生私有派生仍为公有成为私有非法,私有类外不可调用Bb1(10,20);b1.ShowB();第27页/共56页28由于构造函数不能被继承由于构造函数不能
26、被继承,故故派生类的构造函数派生类的构造函数必必须调用基类的构造函数须调用基类的构造函数来初始化基类成员和基类来初始化基类成员和基类子对象子对象。若派生类中含有子对象,则派生类构造函若派生类中含有子对象,则派生类构造函数的调用顺序如下:数的调用顺序如下:基类的构造函数基类的构造函数子对象类的构造函数子对象类的构造函数派生类的构造函数派生类的构造函数5.5 有子对象的派生类的构造函数第28页/共56页29classB:publicAinty;Aa1;public:B(inta,intb):A(a),a1(3)y=b;.;当撤销派生类对象时,析构函当撤销派生类对象时,析构函数的调用正好相反。数的调
27、用正好相反。基类的构造函数基类的构造函数子对象类的构造函数子对象类的构造函数派生类的构造函数派生类的构造函数5.5 有子对象的派生类的构造函数基类成员构造用基类名,基类子对象构造用对象名基类成员构造基类子对象构造第29页/共56页30classBase1intx;public:Base1(inta)x=a;cout调用基类调用基类1的构造函数的构造函数!n;Base1()cout调用基类调用基类1的析构函数的析构函数!n;classBase2inty;public:Base2(inta)y=a;cout调用基类调用基类2的构造函数的构造函数!n;Base2()cout调用基类调用基类2的析构函
28、数的析构函数!n;classDerived:publicBase2,publicBase1intz;public:Derived(inta,intb):Base1(a),Base2(20)z=b;cout调用派生类的构造函数调用派生类的构造函数!n;Derived()cout调用派生类的析构函数调用派生类的析构函数!n;voidmain()Derivedc(100,200);调用基类调用基类2的构造函数的构造函数调用基类调用基类1的构造函数的构造函数调用派生类的构造函数调用派生类的构造函数调用派生类的析构函数调用派生类的析构函数调用基类调用基类1的析构函数的析构函数调用基类调用基类2的析构函数
29、的析构函数先说明基类25.5 有子对象的派生类的构造函数第30页/共56页31classDerived:publicBase2,publicBase1intz;Base1b1,b2;public:Derived(inta,intb):Base1(a),Base2(20),b1(200),b2(a+b)z=b;cout调用派生类的构造函数调用派生类的构造函数!n;Derived()cout调用派生类的析构函数调用派生类的析构函数!n;voidmain()Derivedc(100,200);基类子对象基类成员构造基类子对象构造基类成员构造用基类名,基类子对象构造用对象名5.5 有子对象的派生类的构
30、造函数第31页/共56页32classBase1intx;public:Base1(inta)x=a;cout调用基类调用基类1的构造函数的构造函数!n;Base1()cout调用基类调用基类1的析构函数的析构函数!n;classBase2inty;public:Base2(inta)y=a;cout调用基类调用基类2的构造函数的构造函数!n;Base2()cout调用基类调用基类2的析构函数的析构函数!n;classDerived:publicBase2,publicBase1intz;Base1b1,b2;public:Derived(inta,intb):Base1(a),Base2(2
31、0),b1(200),b2(a+b)z=b;cout调用派生类的构造函数调用派生类的构造函数!n;Derived()cout调用派生类的析构函数调用派生类的析构函数!n;voidmain()Derivedc(100,200);5.5 有子对象的派生类的构造函数第32页/共56页33调用基类调用基类2的构造函数的构造函数调用基类调用基类1的构造函数的构造函数调用派生类的构造函数调用派生类的构造函数调用派生类的析构函数调用派生类的析构函数调用基类调用基类1的析构函数的析构函数调用基类调用基类2的析构函数的析构函数调用基类调用基类1的构造函数的构造函数调用基类调用基类1的构造函数的构造函数调用基类调
32、用基类1的析构函数的析构函数调用基类调用基类1的析构函数的析构函数说明基类1的对象b1,b25.5 有子对象的派生类的构造函数第33页/共56页34冲突冲突ABCxxxDxxxD()dDv;v.x=5;public派生类对象产生了冲突v.A:x=5;用类作用符限定5.6 多重继承引起的二义性第34页/共56页35classApublic:intx;voidShow()coutx=xn;A(inta=0)x=a;classBpublic:intx;voidShow()coutx=xn;B(inta=0)x=a;classC:publicA,publicBinty;public:voidSetx(
33、inta)x=a;/c1对象中有两个对象中有两个x成员成员voidSety(intb)y=b;intGety()returny;voidmain()Cc1;c1.Show();/c1对象中有两个对象中有两个Show()函数函数这时,可以利用这时,可以利用类作用类作用域符域符:来指明数据或函来指明数据或函数的来源。数的来源。如:如:A:x=a;c1.B:Show();5.6 多重继承引起的二义性第35页/共56页36支配规则支配规则AxDpublicxxD()基类成员派生类新增成员Dv;v.x=5;当派生类中新增加的数据或函数当派生类中新增加的数据或函数与基类中原有的同名时,若不加与基类中原有的
34、同名时,若不加限制,则限制,则优先调用派生类中的成优先调用派生类中的成员员,即后面的覆盖前面的即后面的覆盖前面的。55.6 多重继承引起的二义性第36页/共56页37classApublic:intx;voidShow()coutx=xn;classBpublic:inty;voidShow()couty=yn;classC:publicA,publicBpublic:inty;/类类B和类和类C均有均有y的成员的成员;voidmain()Cc1;c1.x=100;c1.y=200;/给派生类中的给派生类中的y赋值赋值c1.B:y=300;/给基类给基类B中的中的y赋值赋值c1.A:Show(
35、);c1.B:Show();/用作用域运算符限定调用的函数用作用域运算符限定调用的函数couty=c1.yn;/输出派生类中的输出派生类中的y值值couty=c1.B:yn;/输出基类输出基类B中的中的y值值当派生类中新增加的当派生类中新增加的数据或函数与基类中数据或函数与基类中原有的同名时,若不原有的同名时,若不加限制,则加限制,则优先调用优先调用派生类中的成员,派生类中的成员,即即后面的覆盖前面的后面的覆盖前面的。5.6 多重继承引起的二义性第37页/共56页38classApublic:intx;A(inta=0)x=a;classBpublic:inty;B(inta=0)y=a;cl
36、assC:publicAintz;Bb1;Aa1;public:C(inta,intb,intm):A(a),b1(b),a1(a+b)z=m;voidShow()coutx=xt;couty=b1.yt;coutx=zn;couta1.x=a1.xendl;voidmain()Cc1(100,200,500);c1.Show();xzShow()a1.xb1.yC的对象所占空间的对象所占空间从基类A中继承在类C中新说明在类C中新说明在类C中新说明在类C中新说明从基类A中继承新说明类A对象中的x5.6 多重继承引起的二义性第38页/共56页39基类与对象成员基类与对象成员任一基类在派生类中只能
37、继承一次,否则,会造成成员名的任一基类在派生类中只能继承一次,否则,会造成成员名的冲突冲突 若在派生类中,确实要有二个以上基类的成员,若在派生类中,确实要有二个以上基类的成员,则可用基类则可用基类的二个对象作为派生类的成员。的二个对象作为派生类的成员。把一个类作为派生类的基类或把一个类的对象作为一个类的把一个类作为派生类的基类或把一个类的对象作为一个类的成员,在使用上是有区别的:成员,在使用上是有区别的:p在派生类中可直接使用基类的成员(访问权限允许的话),在派生类中可直接使用基类的成员(访问权限允许的话),但要但要使用对象成员的成员时,必须在对象名后加上成员运算使用对象成员的成员时,必须在对
38、象名后加上成员运算符符“.”和成员名和成员名。5.6 多重继承引起的二义性第39页/共56页40例题:在平面上作两个点,连一直线,求直线的长度和直例题:在平面上作两个点,连一直线,求直线的长度和直线中点的坐标。要求如下:线中点的坐标。要求如下:基类为基类为Dot,有两个公有数据成员,即平面上的坐标,有两个公有数据成员,即平面上的坐标(x,y),同时有构造函数及打印函数。,同时有构造函数及打印函数。派生类为派生类为Line,有,有两个基类两个基类Dot对象对象,分别存放两点的,分别存放两点的坐标,同时,从坐标,同时,从基类继承了一个基类继承了一个Dot数据数据,存放直线中,存放直线中点的坐标。点
39、的坐标。5.7 应用举例第40页/共56页xyDot(x,y)(构造构造)Dot(&dot)(拷贝拷贝)Show()Dot的对象空间的对象空间x(中点中点)y(中点中点)Show()d1xyShow()d2xyShow()Line(dot1,dot2)Showl()Line对象对象空间空间从基从基类继类继承承基类基类对象对象415.7 应用举例第41页/共56页42classDotpublic:floatx,y;Dot(floata=0,floatb=0)x=a;y=b;voidShow(void)coutx=xty=yendl;classLine:publicDotDotd1,d2;publ
40、ic:Line(Dotdot1,Dotdot2):d1(dot1),d2(dot2)x=(d1.x+d2.x)/2;y=(d1.x+d2.y)/2;voidShowl()coutDot1:;d1.Show();coutDot2:;d2.Show();coutLength=sqrt(d1.x-d2.x)*(d1.x-d2.x)+(d1.y-d2.y)*(d1.y-d2.y);coutendl;coutCenter:x=xty=yendl;voidmain()floata,b;coutab;Dotdot1(a,b);/调用调用Dot的构造函数的构造函数coutab;Dotdot2(a,b);Lin
41、eline(dot1,dot2);line.Showl();用坐标初始化Dot对象在Line中新说明的成员对成员初始化x,y是继承基类的成员打印坐标5.7 应用举例第42页/共56页43基类基类对象对象派生类派生类对象对象赋值兼容规则,即相互之间能否赋值?赋值兼容规则,即相互之间能否赋值?可以将派生类对象的值赋给基类对象。可以将派生类对象的值赋给基类对象。反之不行反之不行Baseb;Derived;b=d;只是将从基类只是将从基类继承来的成员继承来的成员赋值。赋值。5.8 基类与派生类的转换第43页/共56页44Dotdot;Lineline;Dot=line;Line=dot;非法xyDot
42、(x,y)(构造构造)Dot(&dot)(拷贝拷贝)Show()x(中点中点)y(中点中点)Show()d1xyShow()d2xyShow()Line(dot1,dot2)Showl()Line对象空间对象空间从基从基类继类继承承基类基类对象对象Dot的对象空间的对象空间5.8 基类与派生类的转换第44页/共56页45可以将一个派生类对象的地址赋给基类的指针变量。可以将一个派生类对象的地址赋给基类的指针变量。基类对象基类对象派生类对象派生类对象Baseb;Derived;Base*basep;basepbasep=&b;basepbasep=&dbasep只能引用从基类只能引用从基类继承来的
43、成员。继承来的成员。基类指针派生类对象基类对象5.8 基类与派生类的转换第45页/共56页46派生类对象可以初始化基类的引用。派生类对象可以初始化基类的引用。Derived;Base&basei=d;基类对象基类对象派生类对象派生类对象Baseb;Derived;别名baseibasei只能引用从基只能引用从基类继承来的成员。类继承来的成员。基类引用派生类对象5.8 基类与派生类的转换第46页/共56页47classApublic:intx;A(inta=0)x=a;classBpublic:inty;B(inta=0)y=a;classC:publicA,publicBintz;public
44、:C(inta,intb,intm):A(a),B(b)z=m;voidShow()coutx=xt;couty=yt;coutz=zn;voidmain(void)Aa1(100);Bb1(200);Cc1(10,20,50);couta1.x=a1.xendl;coutb1.y=b1.yendl;c1.Show();a1=c1;b1=c1;/派生类对象向基类对象赋值派生类对象向基类对象赋值couta1.x=a1.xendl;coutb1.y=b1.yShow();xyzC()Show()102050a1.x=100b1.y=200 x=10y=20z=50a1.x=10b1.y=20c1x
45、A()a1yB()b11002001020错误!第47页/共56页48类类B是类是类A的派生类的派生类xA()xA()yB()xA()zC()A类类B类类C类类dxD()xA()zC()yB()A()xD类类类A拷贝类类C是类是类A的派生类的派生类类D是类B和类C的派生类这样,类D中就有两份类A的拷贝B类类C类类类A拷贝5.9 虚基类第48页/共56页49这种同一个公共的基类在这种同一个公共的基类在派生类中产生多个拷贝,派生类中产生多个拷贝,不仅多占用了存储空间,不仅多占用了存储空间,而且可能会造成多个拷贝而且可能会造成多个拷贝中的数据不一致中的数据不一致和模糊的和模糊的引用引用。Dd;d.x
46、=10;/模糊引用模糊引用dxD()xA()zC()yB()A()xD类类类A拷贝B类类C类类类A拷贝5.9 虚基类第49页/共56页50classApublic:intx;A(inta=0)x=a;classB:publicApublic:inty;B(inta=0,intb=0):A(a)y=b;classC:publicApublic:intz;C(inta,intc):A(a)z=c;classD:publicB,publicCpublic:intdx;D(inta1,intb,intc,intd,inta2):B(a1,b),C(a2,c)dx=d;voidmain()Dd1(10,
47、20,30,40,50);coutd1.xendl;dxD()xA()zC()yB()A()xD类类a1=10b=20a2=50c=30dx=40模糊引用,错误!5.9 虚基类第50页/共56页51在多重派生的过程中,若使公共基类在派生类中只在多重派生的过程中,若使公共基类在派生类中只有一个拷贝,则可将这种基类说明为有一个拷贝,则可将这种基类说明为虚基类虚基类。在派生类的定义中,只要在基类的类名前加上关键在派生类的定义中,只要在基类的类名前加上关键字字virtual,就可以将基类说明为虚基类,就可以将基类说明为虚基类。classB:publicvirtualApublic:inty;B(int
48、a=0,intb=0):A(b)y=a;5.9 虚基类第51页/共56页52xA()xA()yB()xA()zC()A类类B类类C类类xA()yB()zC()dxD()D类类一份拷贝,在D()的构造函数中直接调用A()由虚基类派生出的对象初由虚基类派生出的对象初始化时,始化时,直接调用直接调用虚基类虚基类的构造函数。因此,若将的构造函数。因此,若将一个类定义为虚基类,一个类定义为虚基类,则则一定有正确的构造函数可一定有正确的构造函数可供所有派生类调用。供所有派生类调用。5.9 虚基类第52页/共56页53classApublic:intx;A(inta=0)x=a;classB:publicv
49、irtualApublic:inty;B(inta=0,intb=0):A(a)y=b;classC:publicvirtualApublic:intz;C(inta=0,intc=0):A(a)z=c;classD:publicB,publicCpublic:intdx;D(inta1,intb,intc,intd,inta2):B(a1,b),C(a2,c)dx=d;voidmain(void)Dd1(10,20,30,40,50);coutd1.xendl;d1.x=400;coutd1.xendl;coutd1.yendl;040020没有对虚基类构造函数的调用,用缺省的构造函数,A(a2)直接在派生类中调用虚基类的构造函数5040020第53页/共56页54再次强调,用虚基类进行多重派生时,再次强调,用虚基类进行多重派生时,若虚基类没若虚基类没有缺省的构造函数有缺省的构造函数,则在每一个派生类的构造函数,则在每一个派生类的构造函数中中都必须有对虚基类构造函数的调用都必须有对虚基类构造函数的调用(且首先调用)(且首先调用)。5.9 虚基类第54页/共56页作业:P198 第1-8,10题第55页/共56页感谢您的欣赏!第56页/共56页
限制150内