1.相关概念
面向对象程序设计有4个主要特点:抽象、封装、继承和多态性。其中,继承性为其最重要的特征。
在C++中,“继承”就是在一个存在的类的基础上建立一个新的类。已存在的类称为“基类”或“父类”。新建立的类称为“派生类”或“子类”。
派生与继承是一对相对的词,一个新类从已有类那里获得其已有的特性,叫作继承,那么,从另一个角度来说,从已有类产生一个新的子类,就叫做派生。
一个派生类只由一个基类派生,称为单继承;一个派生类由两个或多个基类派生,称为多重继承。从以上所说,我们可以大致的看出派生类与基类的关系:派生类是积累的具体化,而基类则是派生类的抽象。
2.派生类的声明
声明派生类的一般方式为:
class 派生类名:[继承方式] 基类名
{
派生类新增的成员
};
继承方式包括:public(公用的),private(私有的),protected(受保护的),继承方式可不写,不写则默认为private(私有的)。
不同的继承方式会使派生类中的、从基类中继承过来的成员的、访问属性不同。具体在第4小节展开说明。
3.派生类的构成
派生类的成员包括从基类继承过来的成员和自己增加的成员两个部分,但是并不是说把基类的成员和派生类新增的成员简单相加就是派生类了。构造一个派生类包括以下3个部分:
(1)从基类接收成员
这里要注意的是派生类必须全部接受基类的成员,即不可以选择性的接受基类的成员。
(2)调整从基类接收的成员
这里有两个方面,第一方面是可通过指定的继承方式,改变基类成员在派生类中的访问属性;另一方面,是在派生类中声明一个与基类同名的成员,则派生类中新成员会覆盖掉基类中的同名成员。(注:若是成员函数,不仅要使函数名相同,参数的个数与类型也要相同,否则,则为函数重载而非覆盖。)
(3)在声明派生类时增加的成员
在声明派生类时 ,一般还应当自己定义派生类的构造函数和析构函数,因为构造函数和析构函数是不能从基类继承的。
4.派生类成员的属性
因派生类中即有基类成员又有派生类新增成员,所以就产生了这两部分成员的关系和访问属性的问题。
派生类新增成员的属性一般在定义时就确定了,而基类成员在派生类的访问属性,不仅要考虑在基类中该成员所声明的访问属性,还要考虑派生类所声明的对积累的继承方式。在第2节的时候提到,在派生类中,对积累的继承方式包括:public(公用的),private(私有的),protected(受保护的)三种,下面我们详细介绍这三种继承方式。
在介绍三种继承方式之前,先让我来建立一个基类Student如下:
#ifndef STUDENT
#define STUDENT
#include
#include
using namespace std;
class Student
{public:
void getvalue(){
cin>>num>>name>>sex;}
void display(){
cout<<"num:"<
<
4.1公有继承
在定义一个派生类时,继承方式指定为public的,称为公有继承,用公有继承方式建立的派生类称为公有派生类(public derived class),其基类称为公有基类(public class)。
公有派生类的成员在派生类中的访问属性见下表1.1
表1.1 公用基类的成员在派生类中的访问属性
在基类的访问属性 继承方式 在派生类中的访问属性 private(私有) public(公用) 不可访问 public(公用) public(公用) public(公用) protected(保护) public(公用) protected(保护)
下面我们通过代码来看看公用继承的性质:
首先,我们先定义一个公有继承的派生类Student1:
#ifndef STUDENT1
#define STUDENT1
#include"class.h"
#include
#include
using namespace std;
class Student1:public Student
{public:
void getvalue_1(){
cin>>age>>addr;}
void display_1(){
// cout<<"num:"<
<
在以上的代码中我们可以看出:公有派生类不可以直接调用公有基类的私有成员。 那么问题来了,如何通过公有派生类调用公有基类的私有成员呢?我们来看看下面的代码:
#include"class.h"
#include"class1.h"
#include
using namespace std;
int main(){
Student1 s1;
s1.getvalue(); //调用基类的公有成员函数
s1.getvalue_1(); //调用派生类的公有成员函数
s1.display(); //调用基类的公有成员函数
s1.display_1(); //调用派生类的公有成员函数
return 0;}
由以上代码,我们可以看到,公有派生类可以通过调用公有派生类的公有成员函数,来间接地调用公有基类的私有成员。 4.2私有继承
在定义一个派生类时,继承方式指定为private的,称为私有继承,用私有继承方式建立的派生类称为私有派生类(private derived class),其基类称为私有基类(private class)。
私有派生类的成员在派生类中的访问属性见下表1.2
表1.2 私用基类的成员在派生类中的访问属性
在基类的访问属性 继承方式 在派生类中的访问属性 private(私有) private(私有) 不可访问 public(公用) private(私有) private(私有) protected(保护) private(私有) private(私有)
下面我们定义一个私有派生类Student2:
#ifndef STUDENT2
#define STUDENT2
#include"class.h"
#include
#include
using namespace std;
class Student2:private Student
{public:
void getvalue_2(){
cin>>num>>name>>sex;}
void display_2(){
cout<<"age:"<
<
再看看如下主函数:
#include"class.h"
#include"class2.h"
#include
using namespace std;
int main(){
Student2 s2;
s2.display_2(); //调用派生类的公有成员函数
//s2.display(); //错误,私有基类的公有成员函数在派生类中是私有函数,所以不能在类外调用
//s2.age=18; //错误,派生类的私有成员不能在外界调用
return 0;}
从中我们得出了结论:(1)不能通过私有派生类对象调用从私有基类继承过来的任何成员(如以上主函数的错误一)。
(2)私有派生类的成员函数还是可以调用私有基类的公有成员的。
从结论(1)、(2)中,我们可以推知:虽然在派生类外,我们不能通过派生类对象调用私有基类的公有成员函数(结论(1)),但是可以通过私有派生类的成员函数调用私有基类的公用成员函数(结论(2))。
具体例子:
#ifndef STUDENT2
#define STUDENT2
#include"class.h"
#include
#include
using namespace std;
class Student2:private Student
{public:
void getvalue_2(){
getvalue();
cin>>age>>addr;}
void display_2(){
display();
cout<<"age:"<
<
在以上代码中,在私有派生类的公用函数中调用了私有基类的公用成员函数,从而间接地调用了私有基类的私有成员。
4.3保护继承
在定义一个派生类时,继承方式指定为protect的,称为保护继承,用保护继承方式建立的派生类称为保护派生类(protected derived class),其基类称为保护基类(protected class)。
由protect声明的成员称为“受保护的成员”,或简称“保护成员”。保护成员不能被类外访问,可以被派生类的成员函数直接调用。
保护派生类的成员在派生类中的访问属性见下表1.3
表1.3 保护基类的成员在派生类中的访问属性
在基类的访问属性 继承方式 在派生类中的访问属性 private(私有) protected(保护) 不可访问 public(公用) protected(保护) protected(保护) protected(保护) protected(保护) protected(保护)
下面比较一下私有继承和保护继承
在一次的继承中,私有继承和保护继承实际上起的作用都是一样的,即在类外不能访问任何成员,而派生类中可以通过成员函数访问基类中的公用成员和保护成员。但如果继续派生,在新的派生类中,两种继承的派生类就不一样了。再派生一次,原先的私有派生类的所有成员都变不可访问,而原先的保护派生类的公用成员和保护成员变为保护成员,还可以被派生类的成员函数调用。
4.4在派生类中,成员的访问属性
如下表1.4
派生类中的访问属性 在派生类中 在派生类外部 在下一层公用派生类中 公用 可以 可以 可以 保护 可以 不可以 可以 私有 可以 不可以 不可以 不可访问 不可以 不可以 不可以
注:在讨论一个成员的访问属性时,要注意前提,就是在哪一个作用域中。同一个成员在不同的作用域中是可以表现出不同的访问属性的。
5.多级派生(相关概念)
类A为基类,类B是类A的派生类,类C是类B的派生类,则类C也是类A的派生类。类B称为类A的直接派生类,类C称为类A的间接派生类。类A是类B的直接基类,是类C的间接基类。
在多级派生中,如果采用私有继承方式,派生若干次后,基类的所有成员都会变得不可访问;而如果采用保护继承派生若干次,由于派生类外是无法访问派生类中的任何成员的,所以很难记清楚哪些成员可以访问,哪些成员不可以访问,容易出错。所以,在实际应用中,常用的是公用继承。
参考资料:C++程序设计(第2版).谭浩强.清华大学出版社.2011.8.pag:333-359