第六章 继承和派生

第六章 继承和派生

6.1 继承和派生的基本概念

这种通过特殊化已有的类来建立新类的过程,叫做“类的派生”,原来的类叫做“基类”,新建立的类则叫做“派生类”。另一方面,从类的成员角度看,派生类自动地将基类的所有成员作为自己的成员,这叫做“继承”。基类和派生类又可以分别叫做“父类”和“子类”,有时也称为“一般类”和“特殊类”。

从一个或多个以前定义的类(基类)产生新类的过程称为派生,这个新类称为派生类。派生的新类同时也可以增加或者重新定义数据和操作,这就产生了类的层次性。

类的继承是指派生类继承基类的数据成员和成员函数。继承常用来表示类属关系,不能将继承理解为构成关系。

当从现有的类中派生出新类时,派生类可以有以下几种变化:

(1)增加新的成员(数据成员或成员函数)

(2)重新定义已有的成员函数

(3)改变基类成员的访问权限

C++派生类使用两种基本的面向对象技术:第一种称为性质约束,即对基类的性质加以限制;第二种称为性质扩展,即增加派生类的性质。

C++中有两种继承:单一继承和多重继承。对于单一继承,派生类只能有一个基类;对于多重继承,派生类可以有多个基类。

6.2 单一继承

6.2.1 单一继承的一般形式

C++,声明单一继承的一般形式如下:

class 派生类名:访问控制 基类名{

private:

成员声明列表

protected:

成员声明列表

public:

成员声明列表

};

这里和一般的类声明一样,用关键字class声明一个新的类。冒号后面的部分指示这个新类是哪个基类的派生类。所谓“访问控制”是指如何控制基类成员在派生类中的访问属性。它是3个关键字publicprivateprotected中的一个。一对大括号“{}”是用来声明派生类自己的成员的。

6.2.2 派生类的构造函数和析构函数

定义派生类的构造函数的一般形式如下:

派生类名::派生类名(参数表0) 基类名(参数表)

{...//函数体}

冒号后“基类名(参数表)”称为成员初始化列表,参数表给出所调用的基类构造函数所需要的实参。实参的值可以来自“参数表0”,或由表达式给出。

构造函数(包括析构函数)是不被继承的,所以一个派生类只能调用它的直接基类的构造函数。当定义派生类的一个对象时,首先调用基类的构造函数,对基类成员进行初始化,然后执行派生类的构造函数,如果某个基类仍是一个派生类,则这个过程递归执行。该对象消失时,析构函数的执行顺序和执行构造函数的顺序正好相反。

6.2.3 类的保护成员

C++语言规定,使用公有方式产生的派生类成员函数可以直接访问基类中定义的或从另一个基类继承来的公有成员,但不能访问基类的私有成员。

在类的声明中,关键字protected之后声明的是类的保护成员。保护成员具有私有成员和公有成员的双重角色;对派生类的成员函数而言,它是公有成员,可以被访问;而对其他函数而言则仍是私有成员,不能被访问。

6.2.4 访问权限和赋值兼容规则

1.公有派生和赋值兼容规则

在公有派生的情况下,基类成员的访问权限在派生类中保持不变。这就意味着:

(1)基类的公有成员在派生类中依然是公有的。

(2)基类的保护成员在派生类中依然是保护的。

(3)基类的不可访问的和私有的成员在派生类中也仍然时不可访问的。

当希望类的某些成员能够被派生类所访问,而又不能被其他的外界函数访问的时候,就应当把它们定义为保护的。

所谓赋值兼容规则是指在公有派生情况下,一个派生类的对象可以作为基类的对象来使用的情况。

注意:静态成员可以被继承,这时基类对象和派生类的对象共享该静态成员。

2.isa”和“has-a”的区别

类与类之间的关系有两大类:一是继承和派生问题,二是一个类使用另一个类的问题。后者的简单用途是把另一个类的对象作为自己的数据成员或者成员函数的参数。

对于继承,首先要掌握公有继承的赋值兼容规则,理解公有继承“就是一个(isa)”的含义。

分层也可以叫做包含、嵌入或者聚合。公有继承的意思是“isa”。与此相反,分层的意思是指“has-a(有一个)”。

3.公有继承存取权限表

注意:静态成员可以被继承,这时,基类对象和派生类的对象共享该静态成员。

4.私有派生

通过私有派生,基类的私有和不可访问成员在派生类中是不可访问的,而公有和保护成员这时就成了派生类的私有成员,派生类的对象不能访问继承的基类成员,必须定义公有的成员函数作为接口。更重要的是,虽然派生类的成员函数可通过定义自定义的函数访问基类的成员,但将派生类作为基类在继续派生时,这时即使使用公有派生,原基类公有成员在新的派生类中也将是不可访问的。

5.保护派生

派生也可以使用protected。这种派生使原来的权限都降一级使用,即private变为不可访问;protected变为privatepublic变为protected。因为限制了数据成员和成员函数的访问权限,所以用的比较少。它与private继承的主要区别在于下一级的派生中。

6.3 多重继承

一个类从多个基类派生的一般形式如下:

class 类名1:访问控制 类名2,访问控制 类名3,...,访问控制 类名n

{...//定义派生类自己的成员};

6.4 二义性及其支配规则

对基类成员的访问必须是无二义性的,如使用一个表达式的含义能解释为可访问多个基类中的成员,则这种对基类成员的访问就是不确定的,称这种访问具有二义性。

6.4.1 作用域分辨符和成员名限定

从类中派生其他类可能导致几个类使用同一个成员函数名或数据成员名。程序必须确切地告诉编译器使用哪个版本的数据成员或成员函数。

如果基类中的名字在派生类中再次声明,则派生类中的名字隐藏了基类中的相应名字。C++可以迫使编译器“看到”当前作用域的外层部分,存取那些被隐藏的名字,这是由作用域分辨运算符“::”实现的(简称作用域运算符)。这一过程叫做作用域分辨。作用域分辨操作的一般形式如下:

类名::标识符

“类名”可以是任意基类或派生类名,“类标识符”是该类中声明的任一成员名。

6.4.2 派生类支配基类的同名函数

基类的成员和派生类新增的成员都具有类作用域,基类在外层,派生类在内层。如果这时派生类定义了一个和基类成员函数同名的新成员函数(因为参数不同属于重载,所以这里是指具有相同参数表的成员函数),派生类的新成员函数就覆盖了外层的同名成员函数。在这种情况下,直接使用成员函数名只能访问派生类的成员函数,只有使用作用域分辨,才能访问基类的同名成员函数。

派生类D中的名字N支配基类B中同名的名字N,称为名字支配规则。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值