第5章 继承与派生
面向对象程序设计有4个特点:抽象、封装、继承和多态性。前面3章学习了对类和对象的最基本操作,对抽象性和封装性有了足够的认识。下面我们要来了解继承性和多态性。
继承是C++语言的一种重要机制,该机制自动地为一个类提供来自另一个类的操作和数据结构,这使得程序员只需在新类中定义已有类中没有的成分来建立新类。
有了继承,过去的代码就可以不被丢弃,只要稍加修改就可重用。类的继承使简单的代码慢慢发展到丰富的高级代码,程序会越来越完善,功能越来越强大。
没有继承就等于没有面向对象的程序设计,继承性是面向对象程序设计中最重要的特性。当然继承的过程面临许多问题,下面我们来一一解答。
5.1 继承与派生的概念
C++中可重用性是通过继承来实现的。因此,继承是C++的一个重要组成部分。前面介绍了类,一个类中包含数据成员和成员函数。不同的类中,数据成员和成员函数是不相同的。但有时两个类的内容基本相同或一部分相同。这样自然就想到,能否利用原来声明的类作为基础以减少重复工作量。C++的继承机制就可以解决这个问题。
在C++中,所谓”继承”就是在一个已存在的类的基础上建立一个新的类。已存在的类称为基类或父类。新建立的类称为派生类或子类。
其实在现实生活中就存在继承关系。如下所示。
上图是交通工具的类层次,最顶部的交通工具为基类。这个基类会有飞机类、汽车类、火车类等等,图中只画出了汽车类。汽车类以交通工具类为父类,相对交通工具类来说汽车类是子类。汽车类有三个子类,小汽车类、卡车类、旅行车类,它们以汽车类作为父类,此时交通工具类是它们的祖先类,简称祖类。图中展示了四层结构,从上到下它们是派生的关系,从下到上是继承的关系。
面向对象程序设计可以让你声明一个新类作为另一个类的派生。派生类(也称子类)继承它父类的属性和操作。子类也声明了新的属性和新的操作,剔除了那些不适合于其用途的继承下来的操作。这样,继承可让你重用父类的代码,专注于为子类编写新代码。
那些父类已经存在,在新的应用中,你无须修改父类。所要做的就是派生子类,在子类中做一些增加与修改。这种机制,使重用成为可能。
我们来看P150中类Student和类Student1的定义,这两个类中有很多相同的部分,只是Student1中新增加了二个数据成员,成员函数display也有了一些变化。这样我们可以在Student的基础上加上新的内容来定义Student1,以减少重复工作量。
以上介绍的是最简单的情况:一个派生类只从一个基类派生,这称为单继承,如果一个派生类有两个或多个基类的称为多重继承。
如下图所示为最简单的单继承结构图
A
B
下二个图为最简单的多重继承的结构图
A B A C B C D 5.2 派生类的声明方式
声明派生类的一般形式为:
class 派生类名:[继承方式] 基类名 //继承方式包括public、private(默认)、protected {
派生类新增加的成员 }
派生类对象包括两个部分,一个为基类部分,另一个是派生类部分。派生类部分总是依附于基类的,派生类对象中总是含有基类的成员。
显然,派生类对象比基类对象大,它保存了更多的数据,提供了更多的操作。 //定义书中提供的Student1,Student作为基类。 #include
{cin>>num>>name>>sex;} void display( )
{cout<<\ cout<<\ cout<<\ private :
int num; string name; char sex; };
class Student1: public Student //声明基类为Student,定义派生类是Student1 {public: Student1()
{cin>>age>>addr;}
void display_1() //新增加的成员函数 { cout<<\ cout<<\ private:
int age; //新增加的数据成员 string addr; //新增加的数据成员 };
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
private: int num; string name; protected: char sex; public: set(int n,string nam,char s) { num=n;name=nam;sex=s; } void display() { cout<<\ cout<<\ cout<<\ } };
class Student1:public Student //公有继承 {
int age; string addr; public: void display1() { //cout<<\ //error,不能访问基类中的私有成员 //cout<<\ //error,不能访问基类中的私有成员 display(); //公有成员可以在派生类中访问 cout<<\ //保护成员可以在派生类中访问 cout<<\ //派生类中私有成员,可以访问 cout<<\ //派生类中私有成员,可以访问 } };
int main() { Student s; s.set(1,\ s.display(); Student1 s1; s1.display1(); return 0; }
由上例可以看出基类在派生类中的访问情况 基类的成员 私有成员 公有成员 保护成员 5.4.2 私有继承
将上例改为私有继承后运行程序可以得到下表 基类的成员 私有成员 公有成员 保护成员 私有派生类中的访问属性 不可访问 可以访问(私有) 可以访问(私有) 公有派生类中的访问属性 不可访问 可以访问(公有) 可以访问(保护) 5.4.3 保护继承 将上例改为保护继承后运行程序可以得到下表
在类中,还有一种保护(protected)型的访问控制符,保护成员与私有成员一样,不能被使用类的程序员进行访问(也就是可以在类外访问),但可以被类内部的成员函数访问。除此之外,派生类成员是可以访问的,这就是与私有成员的区别所在。 基类的成员 私有成员 公有成员 保护成员 综合以上三张表,可得出以下的表 基类中的成员 公有派生 私有派生 保护派生 私有派生类中的访问属性 不可访问 可以访问(保护) 可以访问(保护)
百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说综合文库第5章 继承与派生在线全文阅读。
相关推荐: