类的派生与继承

目录

一、继承与派生的几个概念

二、继承与派生机制的主要目的

三、派生

四、继承 

访问控制(继承)方式

类内部成员访问控制属性

三种继承方式的详细介绍

四、类型兼容规则

五、派生类的构造、析构函数


一、继承与派生的几个概念

  1. 保持已有类的特性而构造新类的过程称为继承。
  2. 在已有类的基础上新增自己的特性产生新类的过程成为派生。
  3. 被继承的已有类称为基类或父类、超类
  4. 派生出的新类称为派生类或子类。
  5. 一个基类可以派生出多个派生类,每一个派生类又可以作为基类再派生出新的派生类,因此基类和派生类是相对而言的

二、继承与派生机制的主要目的

  1. 继承的目的:避免公共代码的重复开发,在减少代码和数据冗余的同时,节省程序开发的时间,提高程序开发的效率和质量。
  2. 派生的目的:通过增强代码的一致性来件少模块间的接口和界面;当新的问题出现,原有的程序无法解决(或者不能解决)时,需要对原有程序进行改进。

三、派生

构造一个派生类的工作:

  1. 从基类接受成员。派生类把基类全部的成员(不包括构造函数和析构函数)接收过来。
  2. 调整从基类接收的成员。接收基类成员是程序人员不能选择的,但是程序人员可以对这些成员作某些调整,包括基类成员的访问控制(继承方式)、对基类数据或函数成员的隐藏或覆盖。
  3. 在声明派生类时增加的数据成员、函数成员。
  4. 自己定义派生类的构造函数和析构函数,因为构造函数和析构函数是不能从基类继承的。

在派生类中,成员有四种不同的访问属性:

  1. 公有的,派生类内和派生类外都可以访问。
  2. 受保护的,派生类内可以访问,派生类外不能访问,下一层的派生类可以访问(protected)。
  3. 私有的,派生类内可以访问,派生类外不能访问。
  4. 不可访问的(inaccessible),派生类内和派生类外都不能访问(基类中的private成员)。

四、继承 

访问控制(继承)方式

对于派生类而言,不同继承方式对从基类继承成员的访问权限的影响主要体现在两方面:

  1. 派生类新增成员对从基类从基类继承成员的访问权限
  2. 在派生类外部(非族类成员),通过派生类对象对从基类继承成员的访问权限

类内部成员访问控制属性

public成员:可以被程序中任何代码(包括函数)访问

private成员:只能被本类的成员函数和友元函数访问

protected成员:仅可以被本类及其派生类的所有非静态成员函数和友元函数直接访问。

因此,对于那些既要对外界隐藏,又要能被派生类访问的成员,可将它们声明为保护成员。

如果在一个类中声明了保护成员,就意味着该类可能要用作基类,在它的派生类中会访问这些成员。

三种继承方式的详细介绍

  • 公有继承public
  1. 基类的public和protected成员的访问属性在派生类中保持不变。
  2. 基类的private成员不可直接访问
  3. 派生类中的成员函数、友元函数可以直接访问基类中的public和protected成员
  4. 类族之外,通过派生类的对象只能访问基类的public成员,无法直接访问基类的privtae、protected成员。
  • 私有继承private
  1. 基类的public和protected成员都以private身份出现在派生类中。
  2. 基类的private成员不可直接访问。
  3. 派生类中的成员函数、友元函数可以直接访问基类中的public和protected成员
  4. 类族外,不能直接访问基类中的任何成员。因此,私有继承后,基类的成员再也无法在以后的派生类中发生作用,相当于终止了基类功能的继续派生。一般私有继承使用较少。
  • 保护继承protected
  1. 基类的public和protected成员都以protected身份出现在派生类中。
  2. 基类的private成员不可直接访问。
  3. 派生类中的成员函数、友元函数可以直接访问基类中的public和protected成员。
  4. 通过派生类的对象不能直接访问基类中的任何成员。

四、类型兼容规则

一个公有派生类的对象在使用上可以被当作基类的对象,反之则禁止。具体表现在:

  1. 派生类的对象可以隐含转换为基类对象。
  2. 派生类的对象可以初始化基类的引用。
  3. 派生类的指针可以隐含转换为基类的指针。
  • 通过基类对象名、指针只能使用从基类继承的成员
  • 类型兼容,多态的另一重要特色。

补充:

基类与派生类的对应关系

  1. 单继承:派生类只从一个基类派生。
  2. 多继承:派生类从多个基类派生
  3. 多重派生:由一个基类派生出多个不同的派生类。
  4. 多层派生:派生类又作为基类,继续派生新的类。

五、派生类的构造、析构函数

  1. 由于基类的构造函数和析构函数不能被继承,在派生类中,如果对派生类新增的成员进行初始化,就必须为派生类添加新的构造函数。
  2. 但是,派生类的构造函数只负责对派生类新增成员的初始化,对所有从基类继承下来的成员,其初始化工作仍由基类的构造函数完成。
  3. 对派生对象的扫尾、清理工作也需要加入新的析构函数。
  4. 派生类的构造函数需要给基类的构造函数传递参数。
  • 派生类构造函数声明的选择性
  1. 如果对基类初始化,需要调用基类的带有形参表的构造函数时,派生类就必须声明构造函数,提供一个将形参传递给基类构造函数的途径,保证在基类初始化时能够获得必要的数据。派生类构造函数应在初始化列表基类构造函数提供参数
  2. 如果不需要调用基类的带参数的构造函数,也不需要调用新增的成员对象的带参数的构造函数,派生类也可以不声明构造函数,而是采用默认构造函数
  • 构造函数的执行顺序
  1. 调用基类构造函数,调用顺序按照它们被继承时声明的顺序(从左向右)。
  2. 成员对象进行初始化,初始化顺序按照它们在类中声明的顺序
  3. 执行派生类的构造函数体中的内容。
  • 复制/拷贝构造函数
  1. 建立派生类对象时,若没有编写拷贝构造函数,编译器会生成一个隐含的拷贝构造函数。该函数先调用基类的拷贝构造函数,再为派生类新增的成员对象执行拷贝。
  2. 若编写派生类的拷贝构造函数,则需要为基类相应的拷贝构造函数传递参数。
  • 继承时的析构函数
  1. 析构函数也不被继承,派生类可自行声明。
  2. 析构函数无返回类型、无参数、相对简单。声明方法与无继承关系时类的析构函数相同。
  3. 不需要显式地调用基类的析构函数,系统会自动隐式调用。

  • 析构函数的执行顺序
  1. 执行派生类析构函数体中的内容
  2. 调用派生类新增成员对象的析构函数;析构顺序与它们在类中的声明的顺序相反。
  3. 调用基类析构函数:对这些析构函数的调用顺序,恰与构造函数的调用顺序相反。
  • 同名隐藏规则
  1. 对于在不同作用域声明的标识符,可见性原则是:如果存在两个或多个具有包含关系的作用域,外层声明了一个标识符,而内层没有再次声明同名标识符,那么外层标识符在内层仍然可见。
  2. 如果在内层声明了同名标识符,则外层标识符在内层不可见,这时,内层标识符隐藏了外层同名标识符,这种现象称为同名隐藏规则。

派生类中的同名隐藏:

  1. 如果派生类中声明了与基类成员函数同名的新函数,即使函数的参数表不同,从基类继承的同名函数的所有重载形式也都会被隐藏。
  2. 如果某派生类的多个基类拥有同名的成员:
  1. 若派生类又新增这样的同名成员,则派生类成员将隐藏所有基类的同名成员。
  2. 若不新增同名成员,则通过“对象名.成员名”或“对象指针->成员名” 唯一标识成员。
  • 派生类中同名成员的访问

     当派生类与基类中有相同成员时:

  1. 若未强行指名,则通过派生类对象使用的是派生类中的同名成员。

        对象名.成员名 或对象指针->成员名

     2.如要通过派生类对象访问基类中被隐藏的同名成员,应使用基类名限定。

        对象名.类名::成员名(“::”作用域分辨符)对象指针->类名::成员名  

  • 多继承中的二义性问题
  1. 在多继承时,基类与派生类之间,或基类之间出现同名成员时,将出现访问时的二义性(不确定性),可采用虚函数或同名隐藏规则来解决。
  2. 当派生类从多个基类派生,而这些基类又从同一个基类派生,则在访问此共同基类中的成员时,将产生二义性——采用虚基类来解决。
  • 虚基类

虚基类的引入:用于有共同基类的场合

声明形式:以virtual修饰说明基类,例如:class B1:virtual public B

作用:主要用来解决多继承时,可能发生的对同一基类继承多次而产生的二义性问题。

为最远的派生类提供唯一的基类成员,不重复产生多次拷贝

注意:在第一级继承时就要将共同基类设计为虚基类。

  • 虚基类及其派生类构造函数
  1. 建立对象时所指定的类成为最(远)派生类。
  2. 虚基类的成员是由最派生类的构造函数通过调用虚基类的构造函数进行初始化的
  3. 在整个继承结构中,直接或间接继承虚基类的所有派生类,都必须在构造函数的成员初始化表中给出对虚基类的构造函数的调用。如果未列出,则表示调用该虚基类的默认构造函数。
  4. 在建立对象时,只有最派生类的构造函数调用虚基类的构造函数,该派生类的其他基类对虚基类构造函数的调用被忽略。
  • 虚基类的初始化

虚基类初始化时,构造函数的调用顺序规则:

  1. 同一层派生中包含多个虚基类时,虚基类的构造函数按它们派生时声明的先后次序调用。
  2. 如某虚基类是由实基类派生而来,则先调用此实基类的的构造函数,再调用虚基类的构造函数,最后才是派生类的构造函数。
  3. 若同一层派生中,同时存在虚基类与实基类,应先调用虚基类的构造函数,再调用实基类的构造函数,最后调用派生类的构造函数。
  • 组合与继承

概念:通过已有类来构造新类的两种基本方式

  1. 组合:B类中存在一个A类型的内嵌对象

-有一个(has-a)关系:表明每个B类型对象“有一个”A类型对象

-A类型对象与B类型对象是部分与整体关系

-B类型的接口不会直接作为A类型的接口

     2.公有继承:A类是B类的公有基类

-是一个(is-a)关系:表明每个B类型对象“是一个”A类型对象

-A类型对象与B类型对象是一般与特殊关系

(回顾类的兼容性原则:在需要基类对象的任何地方,都可以使用公有派生类的对象来替代)

-B类型对象包括A类型的全部接口

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Momo_159357

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值