C++知识第三篇之继承

news2024/11/27 8:42:47

C++继承

继承是面向对象编程的重要特征,是对类设计层次的复用

文章目录

  • C++继承
    • 一.介绍
      • 1.继承定义
      • 2.继承方式
      • 3.class与struct
    • 二.作用域
      • 1.成员变量
      • 2.成员函数
    • 三.赋值转换
      • 1.给基类对象赋值
      • 2.给基类对象指针赋值
    • 四.派生类的默认函数
    • 五. 其他
      • 1.友元
      • 2.静态
    • 六.继承
      • 1.单继承
      • 2.多继承
      • 3.菱形继承
      • 4.虚拟继承
    • 七.其他
      • 1.如何定义一个不能被继承的类?
      • 2. 菱形继承中如果合理使用虚拟继承?

一.介绍

1.继承定义

class Parent
{};

class Child :public Parent
{};

Parent:是父类,也称作基类(base class);Student:是子类,也称作派生类(derived class)

public:表示继承方式为公共继承

2.继承方式

子类继承父类,有3种继承方式

继承方式的作用是:

对于父类非private的成员,使其在子类中的访问权限为MIN(继承方式,父类成员访问限制符)

如:
在这里插入图片描述
private成员pc在子类中是不可见的,不能在子类中被访问。

  • public继承

    最常用的继承方式,不改变父类成员在子类的访问权限

  • protected继承

    可将父类的public成员,在子类中为protected

  • private继承

    可将父类的public、protected成员,在子类中为private

这个时候可以让我们回顾一下,类中访问限制符的作用

  1. public(公有):其修饰的成员可以在类外直接访问
  2. protected(保护)与private(私有):其修饰的成员不能在类外直接访问

此时就可以发现protected与private的异同了:

如果成员不想在类外被直接访问,则可以用protected或private修饰。但如果需要在子类中被访问,则需要设置为protected。因为private修饰的成员在子类中是不可见(虽然被子类继承了,但是子类不能访问)。

3.class与struct

  • 用class作为类声明的关键字

如果派生类是使用class关键字,则默认继承(不显示表明)方式为private
在这里插入图片描述

  • 用struct作为类声明的关键字

如果派生类是使用struct关键字,则默认继承(不显示表明)方式为private
在这里插入图片描述

无论使用那种,最好显示的写出继承方式

二.作用域

不同类都有其自己的类域,因此基类和派生类都有独立的作用域

例如,上例中的Children类,其继承了Parent类,并继承得到Parent类中的成员,但是这些成员却不在Children的作用域里。

这很好理解,毕竟有两个{},基类成员都在基类的类体中声明(定义)。其次,我们可以在派生类中,声明(定义)与基类同名的成员。(要知道在相同作用域中,定义同名的变量是会引起命名冲突的)


如果派生类和基类中有同名成员,派生类成员将屏蔽对基类同名成员的直接访问,即会优先访问派生类的成员,也称隐藏重定义

此时访问基类成员需要显示指定基类的作用域

1.成员变量

在这里插入图片描述

c.pa:访问的是Children中的成员pa c.Parent::pa:访问到Parent中的成员pa

2.成员函数

需要注意的是如果是成员函数的隐藏,只需要函数名相同就构成隐藏
在这里插入图片描述


在这里插入图片描述

Parent中的show()和Children中的show(),有不同的参数列表,但是并不构成函数重载,因为函数重载的条件是需要在相同作用域中。这两个函数构成隐藏关系

tips:实际中最好不要在继承体系里定义同名成员


三.赋值转换

public继承方式下

派生类的对象可以赋值给基类的对象、基类的指针、基类的引用

这种赋值操作又被叫做切片或者切割,比喻将派生类对象中基类的那部分切给基类进行赋值。

但是基类对象不能赋值给派生类对象

1.给基类对象赋值

在这里插入图片描述

将对象c中Parent部分切片赋值给对象p

2.给基类对象指针赋值

在这里插入图片描述

pp指向对象c中Parent部分的切片

引用:底层也是指针。

四.派生类的默认函数

对于一个空类,经由编译器处理过后,会为它声明一个默认构造函数、一个拷贝构造函数、一个赋值运算符重载、一个析构函数,且这些函数都是public的。称之为默认成员函数。

默认构造函数:

    会先(在初始化列表的位置)调用基类的默认构造函数,完成基类的创建。

构造函数:

    如果基类没有默认构造函数,则需要在初始化列表显示调用基类的构造函数

拷贝构造函数:

    如果基类和派生类的拷贝构造函数都是编译器生成的,会先(在初始化列表的位置)调用基类的拷贝构造函数。

    如果基类显示定义了,则需要在派生类的拷贝构造函数中显示调用,否则不会完成对基类部分的值拷贝(如果不是在参数列表位置调用的,则会先自动调用基类的默认构造函数,如果基类无默认构造,则会报错)

析构函数:

    析构函数基本上都是当对象的生命周期结束后,由编译器自动调用的。在继承体系中,当一个派生类对象需要释放,会先调用派生类的析构函数,再调用其基类的析构函数。

在这里插入图片描述

五. 其他

1.友元

友元的目的是打破封装,使protected或private的类成员也可以被类外访问

友元关系不能被继承
在这里插入图片描述

友元函数show()并非Parent类的成员函数,只是通过friend关键字同类外产生联系

友元类同理

2.静态

对于基类的静态成员,无论其派生类有多少个,都共用着同一个静态成员
在这里插入图片描述

静态函数同理

六.继承

1.单继承

一个派生类只有一个直接基类的关系称为单继承

class Grandparent
{};
class Parent :public Grandparent
{};
class Children :public Parent
{};

Greadparent–>Parent–>Children,单继承

2.多继承

一个派生类有两个或以上直接基类的关系称为多继承

class Father
{};
class Mother
{};
class Children :public Father, public Mother
{};

Children<—Father & Mother,多继承

对基类的初始化顺序,是根据继承的先后顺序
在这里插入图片描述

Children类的默认构造函数中,在其初始列表位置,即使先调用Mother(),后Father(),结果依旧是按继承的顺序先构造Father,后Mother。(初始化列表的错误使用示例,最好按照声明的次序条列)


多继承有可能会出现二义性的问题
在这里插入图片描述

3.菱形继承

菱形继承是多继承的一种特例

class Grandma
{};
class Father :public Grandma
{};
class Mother :public Grandma
{};
class Children :public Father, public Mother
{};

Father是继承于其Grandma,Mother是继承于其Grandma,

当Children继承Father和Mother后,就间接的继承了两个Grandma对象
在这里插入图片描述

二义性问题
在这里插入图片描述

数据冗余问题

对于派生类如果只是需要一份基类的成员即可,那么菱形继承也会造成数据冗余。例如上例的Children类间接的继承了两份Grandma。
在这里插入图片描述

4.虚拟继承

意义:为解决由菱形继承而导致的数据冗余和二义性问题


示例:

class Grandma
{
public:
    int i;
};
class Father :virtual public Grandma
{};
class Mother :virtual public Grandma
{};
class Children :public Father, public Mother
{};

让Father和Mother,虚拟(virtual)继承Grandma

此时会产生什么变化呢?
在这里插入图片描述

可以看见当Father、Mother虚拟继承后,其首位多出来4个字节的空间,存放着某种数据

在这里插入图片描述

首位置是一个指针,指针内存放着地址,该地址指向一张表。指针是虚基表指针,表是虚基表

虚基表中存放的是偏移量,通过第二个偏移量可以找到基类成员变量的地址

可以看出Father、Mother在虚拟(virtual)继承后,就隐式的增加了一个虚基表指针的成员(属于派生类Father、Mother),且所占空间额外增加了4个字节。


下面来看Children类的变化
在这里插入图片描述

由于Father、Mother都是虚拟继承于Grandma,其各自的虚基表中第二个偏移量都是指向来着于Grandma的成员变量。因此在Children类c中唯有一份Grandma成员变量

解决了数据冗余和二义性问题


在实际中建议避免定义出菱形继承。

七.其他

1.如何定义一个不能被继承的类?

  • 将构造函数私有化

    通过无法实例化来间接使A类无法被继承
    在这里插入图片描述

     因此需要提供一个接口GetA,来返回A类型对象

  • 将析构函数私有化

    通过无法实例化来间接使A类无法被继承
    在这里插入图片描述

  • final

    c++11,不同于前两种,使用final来修饰类后,如果有继承操作就会报错
    在这里插入图片描述

2. 菱形继承中如果合理使用虚拟继承?

在下图的菱形继承中,只对BC类使用虚拟继承,就可以解决数据冗余二义性问题
在这里插入图片描述

如果在菱形继承中,每个继承关系都使用虚拟继承,也可以解决问题,但是没有必要,而且还会使空间增大(虚基表指针),并且性能和复杂度都有问题。

🦀🦀观看~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/573346.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android车载学习笔记1——车载整体系统简介

一、汽车操作系统 汽车操作系统包括安全车载操作系统、智能驾驶操作系统和智能座舱操作系统。 1. 安全车载操作系统 安全车载操作系统主要面向经典车辆控制领域&#xff0c;如动力系统、底盘系统和车身系统等&#xff0c;该类操作系统对实时性和安全性要求极高&#xff0c;生态…

VCSA 和ESXi 6.7.0版本升级

1. VCSA升级步骤 1&#xff09;指定升级包的位置 software-packages stage --iso (如果是从vmware下载补丁&#xff0c;使用CD/DVD来映射ISO映像) 或 software-packages stage --url https://vapp-updates.vmware.com/vai-catalog/valm/vmw/8d167796-34d5-4899-be0a-6daade400…

Yolov8涨点神器:注意力机制---多头上下文集成(Context Aggregation)的广义构建模块,助力小目标检测,暴力涨点

🏆🏆🏆🏆🏆🏆Yolov8魔术师🏆🏆🏆🏆🏆🏆 ✨✨✨魔改网络、复现前沿论文,组合优化创新 🚀🚀🚀小目标、遮挡物、难样本性能提升 🍉🍉🍉定期更新不同数据集涨点情况 2.Context Aggregation介绍 论文:https://arxiv.org/abs/2106.01401 仅…

落地页设计的营销心理学(二)

作为一个营销落地页的设计者&#xff0c;最关注的问题&#xff1a;怎么样设计才能让我的落地页有转化&#xff1f; 当然这可能有很多影响因素。但是&#xff0c;你有没有想过在用户打开落地页时&#xff0c;运用心理学概念留住他们&#xff0c;促使他们完成留资、下载、购买等动…

听我一句劝,不要去外包,干了三年,废了....

先说一下自己的情况&#xff0c;大专生&#xff0c;18年通过校招进入湖南某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…

Python实战基础12-闭包

1、函数的嵌套调用 def testB():print(-------testB start------)print(这里是testB函数执行的代码……)print(-------testB end ------)def testA():print(-----testA start-----)testB()print(-----testA end------) testA() 运行结果&#xff1a; 总结&#xff1a; 一个函…

PoseiSwap 参赛,参与斯坦福、Nautilus等联合主办的 Hackathon 活动

近日&#xff0c;由 Stanford Blockchain Accelerator、Zebec Protocol、 Nautilus Chain、Rootz Lab 共同主办的“ Boundless Hackathon Stanford ” 主题的黑客松活动&#xff0c;目前已接受报名。该活动旨在帮助更多的优质开发者参与到 Web3 世界的发展中&#xff0c;推动链…

顶满,阿里P8架构师独家分享的微服务实战笔记

微服务简介 简而言之&#xff0c;微服务架构风格是一种将单个应用程序开发为“一套小型服务”的方法&#xff0c;每个服务“运行在自己的进程中”&#xff0c;并通过轻量级机制(通常是HTTP资源API)进行通信。这些服务“围绕业务功能构建”&#xff0c;并通过全自动部署机制“独…

Cortex-M0的内核架构

目录 Cortex-M 系列产品线 Cortex-M0结构框图 Cortex-M0特性 Cortex-M0工作模式 Cortex-M0工作状态 Cortex-M0的寄存器 Cortex-M0的中断和异常 Cortex-M0的指令集 Cortex-M 系列产品线 Cortex-M系列是由ARM&#xff08;Advanced RISC Machines&#xff09;开发的一系列…

宁德时代,冷暖自知口难言

作者 | 魏启扬 来源 | 洞见新研社 发布可以“上天”的凝聚态电池、落地能量密度160Wh/kg的钠离子电池、量产系统集成度全球最高的麒麟电池…… 宁德时代在上海车展前后密集发声&#xff0c;坚决捍卫着“宁王”的冠冕。 如果再结合不久前的2022年年报&#xff0c;全年307亿的…

六级备考23天|CET-6|写作技巧1|开头段模版

目录 1 考前注意事项 2 真题参考 3 六级作文三段式 第一段 第二段 第三段 4 名言解释型作文 5 开头段的模版 why 型 6 选择型开头模版 7 国内学校/出国读书 8 团队精神和交流 9 作业 10 抽象意志品质类开头 ​ 11 信任的重要性​ 1 考前注意事项 定位错误 常识干扰 拼凑…

【必读】解密Redis主从同步问题,避免数据不一致!

大家好&#xff0c;我是小米&#xff0c;一个热爱技术的程序员。今天&#xff0c;我要和大家聊一聊Redis中常见的一个问题——主从不一致。作为一款高性能的键值存储系统&#xff0c;Redis主从架构在分布式场景中被广泛应用。然而&#xff0c;由于Redis的特性以及配置不当等原因…

大内存分页用在什么场景下?

此内容可以作为你积累高并发处理技能的一个小小的组成部分。挖掘虚拟内存和内存管理单元更底层的工作原理&#xff0c;以及了解转置检测缓冲区&#xff08;TLB&#xff09;的作用。 了解如何通过内存&#xff0c;提升你的程序性能。什么情况下使用大内存分页&#xff1f; 这道…

【四】设计模式~~~创建型模式~~~建造者模式(Java)

【学习难度&#xff1a;★★★★☆&#xff0c;使用频率&#xff1a;★★☆☆☆】 4.1. 模式动机 无论是在现实世界中还是在软件系统中&#xff0c;都存在一些复杂的对象&#xff0c;它们拥有多个组成部分&#xff0c;如汽车&#xff0c;它包括车轮、方向盘、发送机等各种部件…

【Web服务器集群】企业化架构部署

文章目录 前言一、LMAP架构介绍1.概念2.LAMP构建顺序3.LAMP编译安装4.各组件介绍4.1 Linux4.2 Apache4.3 MySQL4.4 PHP/Perl/Python 二、服务器部署1.Apache部署2.MySQL部署3.PHP部署4.安装论坛 前言 LAMP架构是目前成熟的企业网站应用模式之一&#xff0c;指的是协同工作的一整…

案例分享 | 纽扣电池石墨片厚度及缺陷检测

石墨片是一种导热散热材料&#xff0c;质轻柔软&#xff0c;能够轻松贴合在各种热源点&#xff0c;在新能源、航天、3C电子等领域应用广泛。 汽车钥匙中的纽扣电池也需要使用石墨片&#xff0c;石墨片会有统一的厚度标准&#xff0c;装配过程中表面不可避免地会出现裂纹、划痕…

数据结构与算法—排序算法篇

目录 1、选择排序 1.1、算法思想 1.2、步骤 1.3、算法实现 1.4、算法分析 2、 冒泡排序 2.1、算法思想 2.2、算法实现 2.3、算法分析 2.4、改进冒泡排序 3、插入排序 3.1、算法思想 3.2、算法实现 3.3、算法分析 4、希尔排序 4.1、算法思想 4.2、增长量选定规…

Auto-GPT 迈向智能体的第一步——从信息增强和上下文理解开始

Auto-GPT 的出现&#xff0c;意味着 AI 已经能够在没有人工干扰的情况下独立地完成目标任务。这个在 GitHub 中不断创造历史的项目&#xff0c;正以惊人的速度发展着、变化着。 这样前沿又带有科幻色彩的技术项目&#xff0c;引起了各方关注&#xff0c;开发者、投资人、媒体人…

《操作系统》by李治军 | 实验5.pre - switch_to 汇编代码详解

目录 【前言】 一、栈帧的处理 1. 什么是栈帧 2. 为什么要处理栈帧 3. 执行 switch_to 前的内核栈 4. 栈帧处理代码分析 二、PCB 的比较 1. 根据 PCB 判断进程切换与否 2. PCB 比较代码分析 三、PCB 的切换 1. 什么是 PCB 的切换 2. PCB 切换代码分析 四、TSS 内核…

ChatGPT再起争端,如何应对未来的机器挑战?速来学习解决方法!

AI孙燕姿事件 前些日子&#xff0c;“AI孙燕姿”一度火爆出圈。其实就是有网友使用人工智能技术&#xff0c;利用神似歌星孙燕姿的声音翻唱了不少歌手的代表作&#xff0c;并上传到社交平台上&#xff0c;而其翻唱作品的逼真程度是“甚至换气声都可以模仿”。随着“AI孙燕姿”翻…