您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 薪酬管理 > (C++-面向对象程序设计-谭浩强)第11章-继承与派生
第4篇面向对象的程序设计第11章继承与派生第12章多态性与虚函数第13章输入输出流第14章C++工具第11章继承与派生11.1继承与派生的概念11.2派生类的声明方式11.3派生类的构成11.4派生类成员的访问属性11.5派生类的构造函数和析构函数11.6多重继承11.7基类与派生类的转换11.8继承与组合11.9继承在软件开发中的重要意义面向对象程序设计有4个主要特点:抽象、封装、继承和多态性。要较好地进行面向对象程序设计,还必须了解面向对象程序设计另外两个重要特征——继承性和多态性。在本章中主要介绍有关继承的知识,在第12章中将介绍多态性。面向对象技术强调软件的可重用性(softwarereusability)。C++语言提供了类的继承机制,解决了软件重用问题。11.1继承与派生的概念在C++中可重用性是通过继承(inheritance)这一机制来实现的。继承是C++的一个重要组成部分。一个类中包含了若干数据成员和成员函数。在不同的类中,数据成员和成员函数是不相同的。但有时两个类的内容基本相同或有一部分相同。利用原来声明的类Student作为基础,再加上新的内容即可,以减少重复的工作量。C++提供的继承机制就是为了解决这个问题。在第8章已举了马的例子来说明继承的概念。见图11.1示意。在C++中,所谓“继承”就是在一个已存在的类的基础上建立一个新的类。已存在的类(例如“马”)称为“基类(baseclass)”或“父类(fatherclass)”。新建的类(例如“公马”)称为“派生类(derivedclass)”或“子类(sonclass)”。见图11.2示意。图11.1图11.2一个新类从已有的类那里获得其已有特性,这种现象称为类的继承。通过继承,一个新建子类从已有的父类那里获得父类的特性。从另一角度说,从已有的类(父类)产生一个新的子类,称为类的派生。类的继承是用已有的类来建立专用类的编程技术。派生类继承了基类的所有数据成员和成员函数,并可以对成员作必要的增加或调整。一个基类可以派生出多个派生类,每一个派生类又可以作为基类再派生出新的派生类,因此基类和派生类是相对而言的。以上介绍的是最简单的情况:一个派生类只从一个基类派生,这称为单继承(singleinheritance),这种继承关系所形成的层次是一个树形结构,可以用图11.3表示。图11.3请注意图中箭头的方向,在本书中约定,箭头表示继承的方向,从派生类指向基类。一个派生类不仅可以从一个基类派生,也可以从多个基类派生。一个派生类有两个或多个基类的称为多重继承(multipleinheritance),这种继承关系所形成的结构如图11.4所示。图11.4关于基类和派生类的关系,可以表述为:派生类是基类的具体化,而基类则是派生类的抽象。图11.511.2派生类的声明方式假设已经声明了一个基类Student,在此基础上通过单继承建立一个派生类Student1:classStudent1:publicStudent//声明基类是Student{public:voiddisplay_1()//新增加的成员函数{cout″age:″ageendl;cout″address:″addrendl;}private:intage;//新增加的数据成员stringaddr;//新增加的数据成员};基类名前面有public的称为“公用继承(publicinheritance)”。声明派生类的一般形式为class派生类名:[继承方式]基类名{派生类新增加的成员};继承方式包括:public(公用的),private(私有的)和protected(受保护的),此项是可选的,如果不写此项,则默认为private(私有的)。11.3派生类的构成派生类中的成员包括从基类继承过来的成员和自己增加的成员两大部分。在基类中包括数据成员和成员函数(或称数据与方法)两部分,派生类分为两大部分:一部分是从基类继承来的成员,另一部分是在声明派生类时增加的部分。每一部分均分别包括数据成员和成员函数。图11.6实际上,并不是把基类的成员和派生类自己增加的成员简单地加在一起就成为派生类。构造一个派生类包括以下3部分工作:(1)从基类接收成员。派生类把基类全部的成员(不包括构造函数和析构函数)接收过来,也就是说是没有选择的,不能选择接收其中一部分成员,而舍弃另一部分成员。要求我们根据派生类的需要慎重选择基类,使冗余量最小。事实上,有些类是专门作为基类而设计的,在设计时充分考虑到派生类的要求。(2)调整从基类接收的成员。接收基类成员是程序人员不能选择的,但是程序人员可以对这些成员作某些调整。(3)在声明派生类时增加的成员。这部分内容是很重要的,它体现了派生类对基类功能的扩展。要根据需要仔细考虑应当增加哪些成员,精心设计。此外,在声明派生类时,一般还应当自己定义派生类的构造函数和析构函数,因为构造函数和析构函数是不能从基类继承的。派生类是基类定义的延续。可以先声明一个基类,在此基类中只提供某些最基本的功能,而另外有些功能并未实现,然后在声明派生类时加入某些具体的功能,形成适用于某一特定应用的派生类。通过对基类声明的延续,将一个抽象的基类转化成具体的派生类。因此,派生类是抽象基类的具体实现。11.4派生类成员的访问属性既然派生类中包含基类成员和派生类自己增加的成员,就产生了这两部分成员的关系和访问属性的问题。在建立派生类的时候,并不是简单地把基类的私有成员直接作为派生类的私有成员,把基类的公用成员直接作为派生类的公用成员。实际上,对基类成员和派生类自己增加的成员是按不同的原则处理的。具体说,在讨论访问属性时,要考虑以下几种情况:(1)基类的成员函数访问基类成员。(2)派生类的成员函数访问派生类自己增加的成员。(3)基类的成员函数访问派生类的成员。(4)派生类的成员函数访问基类的成员。(5)在派生类外访问派生类的成员。(6)在派生类外访问基类的成员。对于第(1)和第(2)种情况,比较简单,按第8章介绍过的规则处理,即:基类的成员函数可以访问基类成员,派生类的成员函数可以访问派生类成员。私有数据成员只能被同一类中的成员函数访问,公用成员可以被外界访问。第(3)种情况也比较明确,基类的成员函数只能访问基类的成员,而不能访问派生类的成员。第(5)种情况也比较明确,在派生类外可以访问派生类的公用成员,而不能访问派生类的私有成员。对于第(4)和第(6)种情况,就稍微复杂一些,也容易混淆。这些牵涉到如何确定基类的成员在派生类中的访问属性的问题,不仅要考虑对基类成员所声明的访问属性,还要考虑派生类所声明的对基类的继承方式,根据这两个因素共同决定基类成员在派生类中的访问属性。前面已提到:在派生类中,对基类的继承方式可以有public(公用的),private(私有的)和protected(保护的)3种。不同的继承方式决定了基类成员在派生类中的访问属性。简单地说:(1)公用继承(publicinheritance)基类的公用成员和保护成员在派生类中保持原有访问属性,其私有成员仍为基类私有。(2)私有继承(privateinheritance)基类的公用成员和保护成员在派生类中成了私有成员。其私有成员仍为基类私有。(3)受保护的继承(protectedinheritance)基类的公用成员和保护成员在派生类中成了保护成员,其私有成员仍为基类私有。保护成员的意思是:不能被外界引用,但可以被派生类的成员引用,具体的用法将在稍后介绍。11.4.1公用继承在定义一个派生类时将基类的继承方式指定为public的,称为公用继承,用公用继承方式建立的派生类称为公用派生类(publicderivedclass),其基类称为公用基类(publicbaseclass)。采用公用继承方式时,基类的公用成员和保护成员在派生类中仍然保持其公用成员和保护成员的属性,而基类的私有成员在派生类中并没有成为派生类的私有成员,它仍然是基类的私有成员,只有基类的成员函数可以引用它,而不能被派生类的成员函数引用,因此就成为派生类中的不可访问的成员。公用基类的成员在派生类中的访问属性见书中表11.1。例11.1访问公有基类的成员。下面写出类的声明部分:ClassStudent//声明基类{public://基类公用成员voidget_value(){cinnumnamesex;}voiddisplay(){cout″num:″numendl;cout″name:″nameendl;cout″sex:″sexendl;}private://基类私有成员intnum;stringname;charsex;};classStudent1:publicStudent//以public方式声明派生类Student1{public:voiddisplay_1(){cout″num:″numendl;//企图引用基类的私有成员,错误cout″name:″nameendl;//企图引用基类的私有成员,错误cout″sex:″sexendl;//企图引用基类的私有成员,错误cout″age:″ageendl;//引用派生类的私有成员,正确cout″address:″addrendl;}//引用派生类的私有成员,正确private:intage;stringaddr;};由于基类的私有成员对派生类来说是不可访问的,因此在派生类中的display_1函数中直接引用基类的私有数据成员num,name和sex是不允许的。只能通过基类的公用成员函数来引用基类的私有数据成员。可以将派生类Student1的声明改为classStudent1:publicStudent//以public方式声明派生类Student1{public:voiddisplay_1(){cout″age:″ageendl;//引用派生类的私有成员,正确cout″address:″addrendl;//引用派生类的私有成员,正确}private:intage;stringaddr;};然后在main函数中分别调用基类的display函数和派生类中的display_1函数,先后输出5个数据。可以这样写main函数(假设对象stud中已有数据):intmain(){Student1stud;//定义派生类Student1的对象stud┆stud.display();//调用基类的公用成员函数,输出基类中3个数据成员的值stud.display_1();//调用派生类公用成员函数,输出派生类中两个数据成员的值return0;}请根据上面的分析,写出完整的程序,程序中应包括输入数据的函数。实际上,程序还可以改进,在派生类的display_1函数中调用基类的display函数,在主函数中只要写一行:stud.display_1();即可输出5个数据。11.4.2私有继承在声明一个派生类时将基类的继承方式指定为private的,称为私有继承,用私有继承方式建立的派生类称为私有派生类(privatederivedclass),其基类称为私有基类(privatebaseclass)。私有基类的公用成员和保护成员在派生类中的访问属性相当于派生类中的私有成员,即派生类的成员函数能访问它们,而在派生类外不能访问它们。私有基类的私有成员在派生类中成为不可访问的成员,只有基类的成员函数可以引用它们。一个基类成员在基类中的访问属性和在派生类中的访问属性可能是不同的。私有基类的成员在私有派生类中的访问属性见书中表11.2。图11.7图11.7表示了各成员在派生类中的访问属性。对表11.2的规定不必死记,只需理解:既然声明为私有继承,就表示将原来能被外界引用的成员隐藏起来,不让外界引用,因此私有基类的公用成员和保护成员理所当然地成为派生类中的私有成员。私有基类的私有成员按规定只能被基类的成员函数引用,在基类
本文标题:(C++-面向对象程序设计-谭浩强)第11章-继承与派生
链接地址:https://www.777doc.com/doc-5702998 .html