第5章 继承与派生.docx
- 文档编号:10914181
- 上传时间:2023-02-23
- 格式:DOCX
- 页数:81
- 大小:60.10KB
第5章 继承与派生.docx
《第5章 继承与派生.docx》由会员分享,可在线阅读,更多相关《第5章 继承与派生.docx(81页珍藏版)》请在冰豆网上搜索。
第5章继承与派生
第5章继承与派生
面向对象程序设计有4个特点:
抽象、封装、继承和多态性。
前面3章学习了对类和对象的最基本操作,对抽象性和封装性有了足够的认识。
下面我们要来了解继承性和多态性。
继承是C++语言的一种重要机制,该机制自动地为一个类提供来自另一个类的操作和数据结构,这使得程序员只需在新类中定义已有类中没有的成分来建立新类。
有了继承,过去的代码就可以不被丢弃,只要稍加修改就可重用。
类的继承使简单的代码慢慢发展到丰富的高级代码,程序会越来越完善,功能越来越强大。
没有继承就等于没有面向对象的程序设计,继承性是面向对象程序设计中最重要的特性。
当然继承的过程面临许多问题,下面我们来一一解答。
5.1继承与派生的概念
C++中可重用性是通过继承来实现的。
因此,继承是C++的一个重要组成部分。
前面介绍了类,一个类中包含数据成员和成员函数。
不同的类中,数据成员和成员函数是不相同的。
但有时两个类的内容基本相同或一部分相同。
这样自然就想到,能否利用原来声明的类作为基础以减少重复工作量。
C++的继承机制就可以解决这个问题。
在C++中,所谓”继承”就是在一个已存在的类的基础上建立一个新的类。
已存在的类称为基类或父类。
新建立的类称为派生类或子类。
其实在现实生活中就存在继承关系。
如下所示。
上图是交通工具的类层次,最顶部的交通工具为基类。
这个基类会有飞机类、汽车类、火车类等等,图中只画出了汽车类。
汽车类以交通工具类为父类,相对交通工具类来说汽车类是子类。
汽车类有三个子类,小汽车类、卡车类、旅行车类,它们以汽车类作为父类,此时交通工具类是它们的祖先类,简称祖类。
图中展示了四层结构,从上到下它们是派生的关系,从下到上是继承的关系。
面向对象程序设计可以让你声明一个新类作为另一个类的派生。
派生类(也称子类)继承它父类的属性和操作。
子类也声明了新的属性和新的操作,剔除了那些不适合于其用途的继承下来的操作。
这样,继承可让你重用父类的代码,专注于为子类编写新代码。
那些父类已经存在,在新的应用中,你无须修改父类。
所要做的就是派生子类,在子类中做一些增加与修改。
这种机制,使重用成为可能。
我们来看P150中类Student和类Student1的定义,这两个类中有很多相同的部分,只是Student1中新增加了二个数据成员,成员函数display也有了一些变化。
这样我们可以在Student的基础上加上新的内容来定义Student1,以减少重复工作量。
以上介绍的是最简单的情况:
一个派生类只从一个基类派生,这称为单继承,如果一个派生类有两个或多个基类的称为多重继承。
如下图所示为最简单的单继承结构图
下二个图为最简单的多重继承的结构图
5.2派生类的声明方式
声明派生类的一般形式为:
class派生类名:
[继承方式]基类名//继承方式包括public、private(默认)、protected
{
派生类新增加的成员
}
派生类对象包括两个部分,一个为基类部分,另一个是派生类部分。
派生类部分总是依附于基类的,派生类对象中总是含有基类的成员。
显然,派生类对象比基类对象大,它保存了更多的数据,提供了更多的操作。
//定义书中提供的Student1,Student作为基类。
#include
#include
usingnamespacestd;
classStudent
{public:
Student()
{cin>>num>>name>>sex;}
voiddisplay()
{cout<<"num:
"< cout<<"name: "< cout<<"sex: "< private: intnum; stringname; charsex; }; classStudent1: publicStudent//声明基类为Student,定义派生类是Student1 {public: Student1() {cin>>age>>addr;} voiddisplay_1()//新增加的成员函数 {cout<<"age: "< cout<<"address: "< private: intage;//新增加的数据成员 stringaddr;//新增加的数据成员 }; 5.3派生类的构成 派生类中的成员包括两大部分: 1)基类继承过来的成员2)自己增加的成员。 从基类继承的成员体现了派生类从基类继承而获得的共性,而新增加的成员体现了派生类的个性。 为了形象地表示继承关系,采用图来示意。 P154图5.6 构造一个派生类包括以下3部分工作: ●从基类接收成员。 派生类毫无选择地接收除构造函数和析构函数之外的基类全部成员。 所以声明派生时,要自己定义构造函数和析构函数。 派生类中用不到也继承过来了,造成了数据的冗余,这是C++目前无法解决的问题。 ●调整从基类接收的成员。 可以改变基类成员在派生类中的访问属性;可以在派生类中声明一个与基类成员同名的成员,覆盖基类同名成员。 这里说的同名可不是说名字相同而已,还要参数也完全相同。 ●在声明派生类时增加新的成员。 5.4派生类成员的访问属性 派生类中包含基类和派生类自己增加的成员,这样就得考虑以下6个问题,这6个问题是两个成对的。 ●基类成员函数访问基类成员。 类中可以访问自己的成员,这点是肯定的。 ●派生类的成员函数访问派生类自己增加的成员。 类中可以访问自己的成员,这点也是肯定的。 ●基类的成员函数访问派生类的成员。 基类的成员函数只能访问基类的成员,而不能访问派生类的成员。 ●派生类的成员函数访问基类的成员。 前面提到过,派生类继承了除构造函数的析构函数之外的基类全部成员,那么是不是就可以访问基类中的所有成员了呢? 这与基类的访问属性和继承方式有关。 这是我们要讲解的部分。 ●在派生类外访问派生类的成员。 在类外只能访问该类的公有成员,所以,在派生类外也只可以访问派生类的公有成员,而不能访问派生类的私有成员。 ●在派生类外访问基类的成员。 因为在类外只能访问该类的公有成员,所以在派生类外只能访问继承后仍具有公有成员特性的成员。 这与基类的访问属性和继承方式有关。 这是我们要讲解的部分。 以上6个问题中,只有其中用红色标识的是我们要讨论的。 我们知道这两个问题都与成员的访问属性有关。 访问属性共有3种: public: 公有的。 可以被本类中的成员函数引用,也可以在类外被使用(当然要在作用域内) private: 私有的。 只能被本类中的成员函数引用,类外不能调用。 protected: 不能被类外引用,但可以被派生类的成员函数访问。 我们知道这两个问题还都与继承方式有关。 继承方式共有3种: 1)公有继承public: 基类的公有成员和保护成员在派生类中保持原有访问属性,其私有成员仍为基类私有。 2)私有继承private: 基类的公有成员和保护成员在派生类中成了私有成员。 其私有成员仍为基类私有。 3)受保护的继承protected: 基类的公有成员和保护成员在派生类中成了保护成员,其私有成员仍为基类私有。 从继承方式可以看出,基类中的私有成员仍为基类私有,即派生类中是不能访问的。 下面我们来分别讲述这三种继承方式。 5.4.1公有继承 //自编,为了说明问题,成员共有3种访问属性。 #include #include usingnamespacestd; classStudent { private: intnum; stringname; protected: charsex; public: set(intn,stringnam,chars)//没有用构造函数,派生类无法继承构造函数, { num=n;name=nam;sex=s; } voiddisplay() { cout<<"num: "< cout<<"name: "< cout<<"sex: "< } }; classStudent1: publicStudent//公有继承 { intage; stringaddr; public: voiddisplay1() { //cout<<"num: "< //cout<<"name: "< display();//公有成员可以在派生类中访问 cout<<"sex: "< cout<<"age: "< cout<<"addr: "< } }; intmain() { Students; s.set(1,"Li",'F'); s.display(); Student1s1; s1.display1(); return0; } 由上例可以看出基类在派生类中的访问情况 基类的成员 公有派生类中的访问属性 私有成员 不可访问 公有成员 可以访问(公有) 保护成员 可以访问(保护) 5.4.2私有继承 将上例改为私有继承后运行程序可以得到下表 基类的成员 私有派生类中的访问属性 私有成员 不可访问 公有成员 可以访问(私有) 保护成员 可以访问(私有) 5.4.3保护继承 将上例改为保护继承后运行程序可以得到下表 在类中,还有一种保护(protected)型的访问控制符,保护成员与私有成员一样,不能被使用类的程序员进行访问(也就是可以在类外访问),但可以被类内部的成员函数访问。 除此之外,派生类成员是可以访问的,这就是与私有成员的区别所在。 基类的成员 私有派生类中的访问属性 私有成员 不可访问 公有成员 可以访问(保护) 保护成员 可以访问(保护) 综合以上三张表,可得出以下的表 基类中的成员 公有派生 私有派生 保护派生 私有 不可访问 不可访问 不可访问 公有 可访问(公有) 可访问(私有) 可访问(保护) 保护 可访问(保护) 可访问(私有) 可访问(保护) 从以下的表中可以看出,在直接派生中,可访问情况结果是一样的,但如果再继续派生,它们就会有所不同了。 这个问题在下面的多级派生中讲解。 下面再来看一个实例 //思考题: 自编,继承父类成员的简单实例 #include usingnamespacestd; classPoint { intX,Y; public: voidsetPoint(intx,inty){X=x;Y=y;} voidmove(intxoff,intyoff){X+=xoff;Y+=yoff;} intgetX(){returnX;} intgetY(){returnY;} voiddisplayPoint(){cout< }; classRectangle: publicPoint { intW,H; public: voidsetRectangle(intx,inty,intw,inth){setPoint(x,y);W=w;H=h;} intgetW(){returnW;} intgetH(){returnH;} //voiddisplayRectangle(){cout< 会出现错误吗? 如果有错,该怎么修改? }; intmain() { Rectanglerect; rect.setRectangle(2,3,10,20); rect.move(2,3); //cout< 会出现什么错误? cout< return0; } 从上例我们可以了解到派生类Rectangle从基类Point公有继承,所以继承了基类中的全部公有成员和私有成员(构造函数与析构函数除外),并可以访问基类中的公有成员setPoint、move、getX、getY和displayPoint,此外,它还有比父类多一些的信息,即它有W、H数据成员以及setRectangle、getW、getH、displayRectangle成员函数。 下面来看一下书中的实例。 //例5.3在派生类中引用保护成员 #include #include usingnamespacestd; classStudent//声明基类 {public: //基类公用成员 voiddisplay(); voidget_value(){cin>>num>>name>>sex;} protected: //基类保护成员 intnum; stringname; charsex; }; voidStudent: : display() {cout<<"num: "< cout<<"name: "< cout<<"sex: "< } classStudent1: protectedStudent//用protected继承方式声明一个派生类 {public: voiddisplay1(); voidget_value1(){cin>>age>>addr;} private: intage; stringaddr; }; voidStudent1: : display1() {cout<<"num: "< cout<<"name: "< cout<<"sex: "< cout<<"age: "< cout<<"address: "< } intmain() { Student1stud1;//stud1是派生类student2的对象 stud1.get_value(); stud1.get_value1(); stud1.display1();//display是派生类中的公用成员函数 return0; } 下面再来看一个实例。 //思考题: 自编。 #include #include usingnamespacestd; //------------------------------------- classBase { inta; voidf(){cout< public: intb; voidg(){cout< protected: intc; voidk(){cout< };//----------------------------------- classDerived: publicBase{//改为private、protected,再看结果 public: voiddf(){
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第5章 继承与派生 继承 派生