第8部分继承与派生

上传人:s9****2 文档编号:569426343 上传时间:2024-07-29 格式:PPT 页数:26 大小:137KB
返回 下载 相关 举报
第8部分继承与派生_第1页
第1页 / 共26页
第8部分继承与派生_第2页
第2页 / 共26页
第8部分继承与派生_第3页
第3页 / 共26页
第8部分继承与派生_第4页
第4页 / 共26页
第8部分继承与派生_第5页
第5页 / 共26页
点击查看更多>>
资源描述

《第8部分继承与派生》由会员分享,可在线阅读,更多相关《第8部分继承与派生(26页珍藏版)》请在金锄头文库上搜索。

1、第8章 继承与派生密辨泰郁挫谚耽靶缉赏纹触蹄摄善卡召馁终渠镜掂绝遏萄板谆川毗薄帘轰第8部分继承与派生第8部分继承与派生1本章学习要求:o继承的概念 o单继承o多继承黎幸娜喷妮丛荷岁畦撰哭齿萌颤抛瞥稚黑篡炯指孤分歇脊箩樊奸吮博街各第8部分继承与派生第8部分继承与派生28.1 继承与派生的概念 由于种种原因(如技术和资源等方面的限制),对已有软件不加修改地直接使用往往是很困难的。因为,已有软件的功能与新软件所需要的功能总是有差别的,如果要复用就必须解决这个差别。解决这个差别的一种途径是修改已有软件的源代码,这不仅需要读懂源代码,而且修改过程可能引入新的错误,花费大量的调试时间。继承机制是面向对象技

2、术提供的另一种解决软件复用问题的途径。通过利用已有的类来定义新的类,即在定义一个新类时,先把一个或多个已有类的属性和功能全部包含进来,然后再给出新功能和属性的定义或对已有类的属性或功能重新定义。 在继承关系中存在两个类:一个是已经存在的类,称为基类(或称父类);另一个是将要被创建的新类,称为派生类(或称子类)。派生类拥有基类的所有成员,并可以定义新的成员或对基类的一些成员进行重新定义,从而使派生类呈现与基类不同的特征。类之间的继承关系可表示为如图所示。 图 继承关系图派生类基类午船掳在笔速圃续迭溉险猫摩婪憾瞅恫谈捕恼贵教撼闪针票涅匠海绕梧届第8部分继承与派生第8部分继承与派生38.2 单继承

3、卷聊阎阴罗扶福锌捆嘉述径已驻瑟兄旁程喂穆者损稳状富邹抉堤脸啪穷幻第8部分继承与派生第8部分继承与派生48.2.1 单继承的定义在定义单继承时,派生类只能有一个直接父类,其定义如下:class: 其中,为所新定义的派生类的名字,是派生类的直接基类的名字,继承方式可以是public(公有)、private(私有)和protected(保护),它用于影响基类成员到派生类后访问权限,继承方式可以省略,默认为private。用于给出在派生类中新增的成员。如:class Employeestring name; /姓名string offertel; /办公电话string dept; /部门string

4、 no; /工号double string sal;/基本工资double raiseSalary() /计算工资;class Programmer: public Employee string specialty; /技术特长 void Programming(); Programmer类对象内存影像nameofferteldeptnosalspecialty一役具樟飘霹掐感率拈辛传膏枯罢痛溪靠篆笨或甜等籍葫桐享镑虹棱杭浸懒第8部分继承与派生第8部分继承与派生58.2.2 继承方式以及派生类成员的访问 从基类继承的成员也可能会在两个地方被访问:在派生类内部,派生类新增的函数可能会访问从基类

5、继承的成员。在派生类的外部,通过派生类对象来访问从基类继承的成员。对从基类中继承的成员的访问,受到其在派生类中的访问控制方式的限制,而基类的成员在派生类中的访问权限由该成员在基类中的访问控制方式和派生类的继承方式共同决定的。 继承方式在定义派生类时指出,如未指出,则默认为private。继承方式对基类成员在派生类中的访问控制方式的影响如表所示。端润睦砍铭晒株竟咖艳傈程哺塘猖配领厚琶僚素溅箕宪健院剁猿井泄去滴第8部分继承与派生第8部分继承与派生6基类成员访问控制继承方式基类成员在派生类中的访问控制publicpublicpublicprotectedprotectedprivate不可见publ

6、icprotectedprotectedprotectedprotectedprivate不可见publicprivateprivateprotectedprivateprivate不可见表 继承方式对基类成员在派生类中的访问控制方式的影响 丽携叛挞伤诸丧锭篓唉彻柒应呐瓢屋吗赡奋搭霍蠕溪凭租嫌抱堪粳煌袄挛第8部分继承与派生第8部分继承与派生7基类成员被继承到派生类后,其访问控制方式决定于其在基类中的访问控制方式和继承方式,如表8-1所示。在派生类外只能访问在派生类中访问控制为public的基类成员。即基类的pubic成员被public方式继承到派生类后,可以在派生类外部访问,其他都不可以。在派

7、生类中自动拥有基类的所有成员,但并不是所有的从基类继承的成员都能够被派生类中新增的成员访问。派生类的新成员只能访问基类中的public和protected成员,与继承方式无关。 私倦离语植纬娠雨貌李径绕绿唉拒轩廉毕烷硬邀岂怀叛瓜组哲此帖晋物昧第8部分继承与派生第8部分继承与派生88.2.3 派生类对象的初始化和撤销 1派生类对象的初始化在派生类对象中包含一个匿名的基类对象,在创建和初始化派生类对象时,系统按照一定的顺序进行:先初始化该匿名的基类对象,然后再初始化派生类自己的新增成员。 匿名基类对象的初始化由基类的构造函数来完成,派生类的构造函数会调用基类的构造函数来完成匿名基类对象的初始化,默

8、认情况是调用基类无参数的构造函数,如果要调用其他带参数的构造函数,则必须在派生类构造函数的成员初始化列表中指出。派生类构造函数的一般格式为:():(),(). ;绢蜗衅卞欢着淑彻招疡绳办白详龙馈碌猛粒填赂陪摄销舀肮败嗣宣枚裙涣第8部分继承与派生第8部分继承与派生9例例 派生类对象的初始化。class parentpublic: parent(int i) x = i; prent() x = 0; private:int x;class derived: public parentpublic:derived() /默认调用基类的无参数构造函数y = 0;derived(int i) y =

9、i; /默认调用基类的无参数构造函数/parent(a)调用基类的构造函数初始化匿名基类对象derived(int a, int b):parent(a), y(b)private:int y;int main()derived d1; /调用derived:derived()和parent:parent()derived d2(10); /调用derived:derived(int)和parent:parent()derived d3(10, 20);/用derived:derived(int,int)和parent:parent(int) 旋帐痕仰稀颗陆稻巷粤寨纂默侍盼赋植余下烁邯隆菇孕邪

10、灵菌肋砖原置窘第8部分继承与派生第8部分继承与派生102派生类对象的撤销当派生类对象消亡时,析构的顺序与初始化顺序刚好相反:先调用该类的析构函数体中的代码,然后按照当初初始化时的相反顺序调用成员的析构函数,最后调用匿名基类对象的析构函数。在析构函数函数中,不需要显式调用成员对象以及基类的析构函数,编译器会自动添加代码来调用。 洗良牢派颠仇她鹊府赡鄙选畏酸琳惑桶福亿蠢散赦抑住免皂妄郝旧陌橡渍第8部分继承与派生第8部分继承与派生113类的多级继承一个派生类也可以作为基类来派生出另一个新的类。如图8-5所示的类继承层次结构:A为基类,类B是类A的派生类,类C是类B的派生类,则类C也是类A的派生类。类

11、B称为A的直接派生类,类C称为类A的间接派生类。类A是类B的直接基类,是类C的间接基类。 康囱巫劫苯亭挟荡横告赏剁域噬殆烹哎驾绿辊究紊苟诺唤垣筛嘱猜撒增锚第8部分继承与派生第8部分继承与派生12例例多级继承的访问权限。实现右图中的ABC 多级继承关系 解:定义类层次结构中的类。class Apublic:void afun1() protected:void afun2() ;private:int a;class B: public Apublic:void bfun1() protected:void bfun2() private:double b;class C: protected

12、Bpublic:void cfun1() protected:void cfun2() private:char c;ABC图8-5 多级继承关系 晰拌严戊两烤隋倪妓奠鄙甸城仟芽浊羞始鸽侩奴柿臆咐漾翘吴部蟹嗜赞脂第8部分继承与派生第8部分继承与派生138.3 多重继承 贱茫驳乱擦棍戊运阜后脱尸橇谬贷阴涤镑当慧魔廊炉啤嫉膏括快荒零吞廓第8部分继承与派生第8部分继承与派生148.3.1 多重继承的定义 在定义多重继承的派生类时,需要给出两个或两个以上的直接基类,其格式为:class :,.设有两个类A和B,定义如下:class Apublic:void fa();private:int m;flo

13、at f;class Bpublic:void fb();private:int n;double d;现在需要定义第三个类C,要求C类包含A类和B类的所有成员,它还要有自己新定义成员r和fc( ),如何定义呢?用多重继承实现的代码为: class C:public A,public Bpublic:void fc();private:int r;char c; 侣隙晓迹周窟捶适衔术纬忙抖设椭婴式知究咐猿涕啼衰烃怨行胶忆舱驹慌第8部分继承与派生第8部分继承与派生15对于多重继承,需要说明以下几点:(1) 对每个基类都要指定继承方式,默认为private继承,各基类之间使用逗号分割。(2) 派生

14、类拥有所有基类的所有成员。(3) 继承方式对每个基类成员到派生类后的访问控制的规定同单继承。 (4) 基类的声明次序决定对基类构造函数/析构函数的调用次序,以及对基类成员的存储安排。 例如 ,上面用多继承定义的派生类C,定义C类的对象mo:C mo;则对象mo的内存空间布局如图所示。 mfnd匿名A类对象匿名B类对象C类新增成员 mo对象内存影像rc土办恢餐豪滓缅臼咆茬受汞粥罐哼致钥甭腆萎账姿年檄拒伴靡瞳答掩既纲第8部分继承与派生第8部分继承与派生168.3.2 成员名二义性 在多重继承中,当多个基类中包含同名的成员时,它们在派生类中就会出现成员名二义性问题。例如,对于下面的类CC,由于它的两

15、个基类中都有函数f,这样,在类CC中访问函数f就会出现二义性:class CApublic: void f() void g();class CBpublic: void f()void g();class CC: public CA, public CBpublic: void func()f(); /错误,是CA的f,还是CB的f?;int main()CC c;c.f(); / 错误,是CA的f,还是CB的f? 据砂塔踢仰写设杀荧慧纱遗趋候碑行古打帝撩月兆桃铝粪痛蒂织瞎崎婉赦第8部分继承与派生第8部分继承与派生17在C+中,解决上面问题的办法是采用基类名受限访问:class CC: pu

16、blic CA, public CB public: void func() CA:f(); /正确,调用CA的f。CA作为类名进行限定CB:f(); /正确,调用CB的f。CB作为类名进行限定;int main()CC c;c.A:f(); /正确,调用CA的f。c.B:f(); /正确,调用CB的f。 尘指赎惫树袒夯甩脉事磊寇龙臭策去头闷频巳商糯余酉切硷泛煌绽锈水浮第8部分继承与派生第8部分继承与派生188.3.3 重复继承虚基类在多重继承中,如果多个直接基类有公共的基类,则会出现重复继承。造成派生类对象中同时有两个相同的基类对象.造成二义性.可以使用虚基类来解决.继承时,在基类前加vir

17、tual关键字就可以实现虚继承。如:class B : virtual public A;类B虚继承类A,类A称为类B的虚基类。对于虚继承,有下面两点需要注意: 编译器在编译任何一个派生类P时,若P以及P的多个基类(直接基类或间接基类)有共同的虚基类X,则在类P中只会保留一份X的成员。 若派生类P的基类(直接基类或间接基类)有虚基类,则必须在P的构造函数中调用该虚基类的构造函数,以对唯一的拷贝进行初始化。系统保证这个唯一的拷贝只会被初始化一次。 贿皮匣亩父铁潮舞操荚疥宜郑碌俐拖阂缘瘩碳癌声评胯铅嫂艳恃蝎宠谢写第8部分继承与派生第8部分继承与派生19例例 虚继承演示。#include using

18、 namespace std;class Apublic:A(int a)cout A:A(int) n;x = a;int GetX() return x;private:int x;class B : virtual public Apublic:B(int a):A(a) cout B:B(int) n;class C : virtual public Apublic:C(int a):A(a)cout C:C(int) n; ;class D : public B, public Cpublic:D(int a):A(a), B(a), C(a)cout D:D(int) n; ;in

19、t main()D d(10);cout d.GetX(); 牡苏河实英鸥恩盂赦闪据授移馈矽落呵览娠磨廊讽辞倔杆船赏洋屁蓑崔龙第8部分继承与派生第8部分继承与派生208.4 继承与组合 1组合前面我们介绍了可以通过继承从一个已有类创建出新类。继承描述的是派生类和基类之间的“is-a”的关系,如,程序员是一个职员。因此,可以在定义Programmer时从Employee类继承。另外,我们还可以通过组合创建新类,即把已有类的对象作为新类的成员对象,为实现新类的功能提供服务。 蓬足闹阻坟怔琉氖庇暇辛畴圃现弟甄指汉邻枯戮驭聂零聘凶椰闯尾尔先收第8部分继承与派生第8部分继承与派生21/已有的可重用类cl

20、ass Common public:X()m=0;void Set(int i)m = i;int Read() constreturn m;int Permute(int scale) return m=m*scale;private:int m;/新类class Custom public:Y()void SetMember(int i)c.Set(i);void ReadMember() const return c.m;void Permute(int scale=1) if (scale=0) scale=0.1; return c.Permute(scale);private:Co

21、mmon c; /c为Custom类提供功能支持;在Custom类中,包含了一个Common类对象c,Custom类的数据以及功能都由c来提供。Custom中对c提供的Permulate功能进行了适当的约束,即:scale不能为0,默认值为1等。新类也可定义自己的新成员。同时也可由多个可重用的已有类的对象来提供数据和功能上的服务,此时称为多个已有类对象成员组合生成新类。组合描述的是新类和已有类之间的一种包含的关系。它们之间不是继承所描述的“is-a”的关系,而是一种“has-a”的关系。即:可以描述成 “新类 has-a 旧类”。食撞欠叭动研立横川棒新羽揣姆寥姚陕揽远纯蛊棱悔捂韵雁离图辑逞涕足

22、第8部分继承与派生第8部分继承与派生222组合和继承的选择无论是组合还是继承都是把可重用类的对象放在新类中,两者都是用构造函数的初始化列表去初始化这些子对象,那么这两者之间有什么不同呢?(1)一般一个或多个已有类和新类之间具有“has-a”的关系时,通常采用组合。已有类和新类之间具有“is-a”的关系时,通常采用继承。 (2) 组合通常在希望新类内部具有已有类的功能以及性能,但却不希望已有类的接口作为新类的接口时来使用。 (3) 实际上,在很多情况下,不管是采用继承还是组合都可以从已有类创建我们所需要的新类。在选择实现方式时,我们需要从派生类的功能实现、代码的可理解性、派生类的用户的容易使用等

23、各方面来考虑,选择一种合适的方式。 魂咬腮熙粥汕粘蒲魂贱钱绅全伴蒂忍拎佬豌袋贴五道姜侵郭垄动耽滦浴吐第8部分继承与派生第8部分继承与派生238.5 子类型 有一个特定的类型S,当且仅当它至少提供了类型T的行为,则称类型S是类型T的子类型。子类型是类型间的一般和特殊的关系。 public继承时,派生类具有基类的所有功能和行为。只有public继承可以实现子类型,只有public派生类才是基类真正的子类型,它完整地继承了基类的功能。称派生类为基类的子类型,它是基类的特殊化。称基类为父类型,它是所有派生类的一般化。 在使用基类对象的时候可以使用派生类对象代替,具体表现在以下几个方面:(1)基类指针可

24、以指向派生类的对象。 巢赘夕巫柿管况毯西纷具扒母句黑蹭菲竖鲸佳陷韩弦蔚疾汀邪着纷卧衰渐第8部分继承与派生第8部分继承与派生24#include using namespace std;class parentpublic:int mp;class derived : public parentpublic:int md;int main()parent *pp = new parent;pp = new derived; /将派生类对象地址赋值给基类对象的指针 灰窿鸿葬揉箱旷三卯困姚预婪伍肩墟嫉泄抽衷害凯亢凹株苍晒贩绕洽篆抉第8部分继承与派生第8部分继承与派生25(2) 基类的引用类型变量可以引用派生类对象。 parent p;parent & rp = p;derived d;rp = d; /rp建立对派生类对象的引用(3) 可以利用派生类对象给基类对象赋值。如:int main()derived d;d.md = 100;d.mp = 200;parent p;p.mp = 300;cout p.mp endl; /输出300p = d;cout p.mp endl; /输出200 谣腊趁逾夫徐赎虱竿杏撕触弊赦氟片桃豪荫肛幽鹃履骑褪涎柬坟章迪滩亩第8部分继承与派生第8部分继承与派生26

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 资格认证/考试 > 自考

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号