例子:
学生是一个抽象的概念,具体的有小学生、初中生、高中生等。任何一个学生都具有姓名、身高、体重、性别等属性。而不同阶段的学生在学习时,内容会有所不同。
为了描写小学生、初中生、高中生,可以写三个不同的类,但是会造成部分属性和功能的重复开发。也可以先设计一个学生类,描述出各种学生的共同属性或功能,然后再针对不同种类的学生做细节的修改。显然,第二种做法更为合理。
在C++中,有一种称为继承的方法,使我们可以用一种已经编写好的类来扩写成一个新的类。新的类具有原有类的所有属性和操作,也可以在原有类的基础上作一些修改和增补。继承实质上是源于人们对事物的认知过程:从抽象概念到具体事物。
面向对象的继承性:
如果有一个类,那么可以将其实例化,成为若干个对象。另外,如果希望对这个类加以升级改造,可以将这个类继承,形成派生类(derivedclass),被继承的类则称为基类(base class)。实例化和继承是一个类的两种发展方向。继承能够减少开发程序的工作量,提高类的重用性。
如果把编写一个类看作是一次生产,那么产品(即编写出来的类)可以有两种用途:一种是将产品直接使用,相当于将类实例化;另一种是将产品用于再生产,相当于将类继承。类在不断的继承中变得更为强大、健全。
将链表结点类的实例对象作为链表类的成员数据,这称为对象的组合,它与类的继承是完全不同的概念。继承(Inheritance)是概念的延续,子类和父类一般都是概念扩展的关系,通常把这种关系称为“是”关系。比如:小学生是学生,自行车是交通工具。而对象的组合是因功能需求产生的从属关系,通常把这种关系称为“有”关系。比如:链表有一个头结点,计算机有一个中央处理器。
当一个对象的成员数据是另一个对象的时候,就先运行成员对象的构造函数,再运行父对象的构造函数。
私有和保护:
private(私有)和protected(保护)都能实现类的封装性。private能够对外部和子类保密,即除了成员所在的类本身可以访问之外,别的都不能直接访问。protected能够对外部保密,但允许子类直接访问这些成员。
public、private和protected对成员数据或成员函数的保护程度可以用下表来描述:
继承的方式:
在使用继承之前,必须保证父类是已经定义好的。如果父类是虚无的、没有被定义的,那么子类也就没什么好继承的了。
定义一个子类的语法格式为: class子类名:继承方式父类名;
继承方式有private、public、protected三种。
private是私有继承,或称为私有的实现继承。它主要体现的是父类成员的重用。父类所有的公有、保护成员继承到子类时,类型会发生改变。父类的公有成员在子类中变成了私有成员,父类的保护成员在子类中也变成了私有成员。这时,可以利用从父类继承而来的成员函数来实现子类的成员函数,并且不必担心外部直接访问父类的成员函数,破坏了子类的秩序。比如认为栈是一种特殊的链表,它只能从链表尾部添加或删除结点,栈的压栈和退栈功能可以方便地由链表类的成员函数实现。但是,如果外部还能直接访问从链表类继承而来的成员函数,那么就可以在栈的任何位置插入结点,栈就会被破坏。
public是公有继承,或称为类型继承。它主要体现的是概念的延伸和扩展,父类所有的公有、保护成员都将按部就班地继承到子类中。父类的公有成员在子类中依然是公有的,父类的保护成员在子类中依然是保护的。
protected是保护继承,或称为保护的实现继承。与私有继承类似,它也是体现父类成员的重用。只不过父类的公有成员和保护成员在子类中都变成了保护成员。因此,如果有一个孙类继承了子类,那么父类中的成员也将被继承,成为孙类的保护成员。
子类对象的构造:
父类的成员对象是最先构造的,接着是运行父类的构造函数,最后运行子类的构造函数。也就是说子类对象是在父类对象的基础上扩展而成的。
如果希望把子类的构造函数的参数传递给父类的构造函数时,可以在子类的构造函数定义中用以下格式调用父类的构造函数:
子类名::构造函数名(参数表):父类名(参数表) {语句;}
这样的方法不仅使子类对象的初始化变得简单,并且使子类和父类的构造函数分工明确,易于维护。
子类对象的析构:
析构函数的运行顺序往往是和构造函数的运行顺序相反的。
父类指针与子类对象:
在公有继承情况下父类的对象指针指向子类对象是允许的;子类的对象指针指向父类是禁止的。此外,如果用父类的对象指针指向子类对象,那么这个指针无法使用子类中扩展出的成员。
覆盖(Overlap):
覆盖(Overlap):子类和父类有两个名字和参数列表完全相同的函数