当前位置: 首页 > news >正文

【C++进阶】继承

【C++进阶】继承

🥕个人主页:开敲🍉

🔥所属专栏:C++🥭

🌼文章目录🌼

1. 继承的概念及定义

    1.1 继承的概念

    1.2 继承定义

        1.2.1 定义格式

        1.2.2 继承父类成员访问方式的变化

    1.3 继承类模板

2. 父类和子类对象赋值兼容转换

3. 继承中的作用域

    3.1 隐藏规则:

4. 子类的默认成员函数

    4.1 4个常见默认成员函数

    4.2 实现一个无法被继承的类

5. 继承与友元

6. 继承与静态成员

7. 多继承及灵性继承问题

    7.1 继承模型

    7.2 虚继承

    7.3 多继承中的指针偏移问题

8. 继承和组合

    8.1 继承和组合

1. 继承的概念及定义
    1.1 继承的概念

  继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许我们在保持原有类特性的基础上进行扩展,增加方法(成员函数)和属性(成员变量),这样产生新的类,称子类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的函数层次的复用,继承是类设计层次的复用。

  下⾯我们看到没有继承之前我们设计了两个类Student和Teacher,Student和Teacher都有姓名/地址/电话/年龄等成员变量,都有identity⾝份认证的成员函数,设计到两个类里面就是冗余的。当然他们也有⼀些不同的成员变量和函数,比如老师独有成员变量是职称,学⽣的独有成员变量是学号;学⽣的独有成员函数是学习,老师的独有成员函数是授课

class Teacher
{
public:
    void identity()
    {
        //身份认证
    }
private:
    size_t _age;//年龄
    string _name;//姓名
    string _address;//地址
    string _tel;//电话

    string _title;//学号
};


class Student
{
private:
    size_t _age;//年龄
    string _name;//姓名
    string _address;//地址
    string _tel;//电话

    string _stuid;//职称
};

    下面我们公共的成员都放到Person类中,Student和teacher都继承Person,就可以复用这些成员,就不需要重复定义了,省去了很多麻烦。

class Person
{
public:
public:
    void identity()
    {
        //身份认证
    }

    size_t _age;//年龄
    string _name;//姓名
    string _address;//地址
    string _tel;//电话
};


class Teacher:public Person
{
private:
    string _title;//学号
};


class Student:public Person
{
private:
    string _stuid;//职称
};

    1.2 继承定义
        1.2.1 定义格式

  从上面我们看到,Person是父类,也可以称为基类,Student和Teacher是子类,也可以称为派生类。继承方式如下图:

  可以看到,这里的继承方式所用的关键字和我们访问限定符的关键字是一样的:

        1.2.2 继承父类成员访问方式的变化

  

总结如下:

  子类中的父类成员的访问方式取决于 父类对这些成员的访问限定符与继承方式 中权限较小的。

  比如,父类的成员用private限定,继承方式用public,那么实际上父类中的成员继承到子类中后,也是private,因此子类虽然继承了父类的成员,但是不可访问。

    1.3 继承类模板

  这里我们实现一个栈的类,继承的是库中的vector,因此我们在实现栈的功能:尾插、尾删、获取栈顶元素等操作时,就可以调用vector中的函数。

2. 父类和子类对象赋值兼容转换

  public继承的子类对象可以赋值给父类的对象/父类的指针/父类的引用。这里有个形象的说法叫切片或者切割。寓意把子类中父类那部分切来赋值过去。

  父类对象不能赋值给子类对象。

3. 继承中的作用域
    3.1 隐藏规则:

在继承体系中父类和子类都有独立的作用域。

子类和父类中有同名成员,子类中将会屏蔽对父类中的同名成员的直接访问,这种情况叫隐藏。如果想要访问父类中的同名成员,使用 父类 :: 同名成员  即可访问。

子类和父类中的成员函数只要函数名相同就构成隐藏,不受其他因素限制。

因此在继承体系中不建议定义同名函数。

4. 子类的默认成员函数
    4.1 4个常见默认成员函数

  默认成员函数是指我们不写,编译器会帮我们自动生成,常见的4个默认成员函数有:构造函数、析构函数、拷贝构造函数、operator=。那么在子类中,这4个默认成员函数是如何生成的呢?

  子类的构造函数必须调用父类的构造函数初始化父类的那⼀部分成员。如果父类没有默认的构造函数,则必须在子类构造函数的初始化列表阶段显示调用。

 ② 子类的析构函数会在被调用完成后自动调用父类的析构函数清理父类成员。因为这样才能保证子类对象先清理子类成员再清理父类成员的顺序。

  子类对象初始化时先调用父类对象的构造函数再调用子类对象的构造函数。

  ④ 子类的拷贝构造函数必须调用父类的拷贝构造完成父类的拷贝初始化。

   子类的operator=必须要调用父类的operator=完成父类的复制。需要注意的是子类的operator=隐藏了父类的operator=,所以显示调用父类的operator=,需要指定父类作用域。

    4.2 实现一个无法被继承的类

方法1:将父类的构造函数设为private,因为在构造子类对象时必须要调用父类对象的构造函数,而父类对象的构造函数设为私有无法访问,因此也就无法被继承。

方法2:使用final修饰父类,就不能够被继承了。finale有最后的意思,这里可以理解为最终类。

5. 继承与友元

  友元关系不能继承,也就是说父类友元不能访问子类私有和保护成员

6. 继承与静态成员

  父类定义了static静态成员,则整个继承体系里面只有⼀个这样的成员。无论派生出多少个子类,都只有⼀个static成员实例。

7. 多继承及灵性继承问题
    7.1 继承模型

  单继承:一个子类只有一个父类的情况我们称为单继承。

  多继承:一个子类有两个或者两个以上的父类时称为多继承,多继承对象在内存中存储的方式为:先继承的父类在最前面,后面继承的父类按照顺序排列,子类的成员排在最后。

  菱形继承:菱形继承是多继承的一种特殊情况。

  从上面可以看出,fun2和fun3都继承了fun1,都存有了一份size_t _fun1,而fun0继承了fun2和fun3,因此不可避免地fun0中存有了两份fun1中的size_t _fun1,这就会导致数据冗余和⼆义性。支持多继承就一定会存在菱形继承的问题,实践中使用多继承是务必要小心谨慎。

  这里在访问_fun1时系统报错说fun0::_fun1不明确,也就是这里的两份_fun1,系统也不知道你要访问的是哪一份。这就是二义性问题。

    7.2 虚继承

  那我们在实践中不可避免地要写出菱形继承,但是又想避免数据冗余和⼆义性的问题该如何做呢?这里就需要使用到virtual关键字:

    7.3 多继承中的指针偏移问题

来看一道例题:

关于多继承中指针偏移问题,下面选项正确的是()  

    A. f1==f2==f3      B. f1<f2<f3      C. f1==f3!=f2      D. f1!=f2!=f3

代码:

class fun1
{
public:
    size_t _fun1;
};

class fun2
{
public:
    size_t _fun2;
};


class fun3 :public fun1, public fun2
{
private:
    size_t _fun3;
};


int main()
{
    fun3 f3;

    fun1* f1 = &f3;
    fun2* f2 = &f3;


    return 0;
}

  正确答案:C

  为什么呢?一张图弄明白:

8. 继承和组合
    8.1 继承和组合

继承是一种is-a的关系。意思就是每个子类对象都是一个父类对象,就好比是有血缘关系的父子,儿子有自己不同于父亲之处,同时也一定有与父亲的相同之处,相同之处便是子类继承父类的那一部分。

 继承允许你根据父类的实现来定义子类的实现。这种通过生成子类的复用通常被称为白箱复用
(white-box reuse)。术语“白箱”是相对可视性而言:在继承方式中,父类的内部细节对子类可见
。继承⼀定程度破坏了父类的封装,父类的改变,对子类有很大的影响。子类和父类间的依赖关系
很强,耦合度高。

组合是一种has-a的关系。可以理解为数学中的集合,{1,2,3}和{1,2,3,4,5,6}的关系,前者是后者的子集后者包含前者。

 对象组合是类继承之外的另⼀种复用选择。新的更复杂的功能可以通过组装或组合对象来获得。对象组合要求被组合的对象具有良好定义的接口。这种复用风格被称为黑箱复用(black-box reuse),因为对象的内部细节是不可见的。对象只以“黑箱”的形式出现。组合类之间没有很强的依赖关系,耦合度低。优先使用对象组合有助于你保持每个类被封装。

 优先使用组合,而不是继承。实际尽量多去用组合,组合的耦合度低,代码维护性好。不过也不太那么绝对,类之间的关系就适合继承(is-a)那就用继承,另外要实现多态,也必须要继承。类之间的关系既适合用继承(is-a)也适合组合(has-a),那就用组合。

 很多人说C++语法复杂,其实多继承就是⼀个体现。有了多继承,就存在菱形继承,有了菱形继承就有菱形虚拟继承,底层实现就很复杂,并不像我们想的那么简单,性能也会有⼀些损失,所以最好不要设计出菱形继承。多继承可以认为是C++的缺陷之一,后来的⼀些编程语⾔都没有多继承,如Java。

                                                 创作不易,点个赞呗,蟹蟹啦~

相关文章:

【C++进阶】继承

【C进阶】继承 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;C&#x1f96d; &#x1f33c;文章目录&#x1f33c; 1. 继承的概念及定义 1.1 继承的概念 1.2 继承定义 1.2.1 定义格式 1.2.2 继承父类成员访问方式的变化 1.3 继承类模…...

立体相机镜面重建(一)镜面标定

无论是单目、双目或者是多屏幕镜面重建&#xff0c;都需要事先对屏幕和相机的相对位置进行标定&#xff0c;求得相机到屏幕之间的相对变换关系。如果求得屏幕和相机之间的变换关系呢&#xff1f;接下来是标定流程。 &#xff08;一&#xff09;准备&#xff1a; 1&#xff09…...

【如何有效解决前端Vue中的常见难题】

&#x1f41f;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢编程&#x1fab4; &#x1f419;个人主页&#x1f947;&#xff1a;Aic山鱼&#x1f420;WeChat&#xff1a;z7010cyy &#x1f988;系列专栏&#xff1a;&#x1f3de;️ 前端-JS基础专栏✨前端-Vue框架专栏…...

CLAMP-1靶机渗透测试

一、靶机下载地址 https://www.vulnhub.com/entry/clamp-101,320/ 二、信息收集 1、主机发现 # 使用命令 nmap 192.168.145.0/24 -sn | grep -B 2 "00:0C:29:88:B4:BF" 2、端口扫描 # 使用命令 nmap 192.168.145.0/24 -p- -sV 3、指纹识别 # 使用命令 whatweb …...

JavaScript中的Truthy Falsy值以及等号判断

1.Falsy & Truthy Falsy的值false&#xff0c;0&#xff0c;-0&#xff0c; “”&#xff0c; null&#xff0c; undefined&#xff0c;NaNTruthy的值除了以上之外的其他值 2.等号判断 console.log(10 10); console.log(0 ); console.log(0 false); console.log( fa…...

uniapp——展开和收起

案例展示 代码 后台返回的数据格式如下&#xff1a; {1: "大富科技速度快放假手动阀",2: "第三方斯蒂芬斯蒂芬是的开发时间",4: "45345345",5: "电饭锅电饭锅地方" }<view class"tipTitle">温馨提示</view> &l…...

WebGL2学习(2): GLSL ES 3.0

更多精彩内容尽在 dt.sim3d.cn &#xff0c;关注公众号【sky的数孪技术】&#xff0c;技术交流、源码下载请添加VX&#xff1a;digital_twin123 WebGL 2.0 给 GLSL 带来了重大变化。WebGL 1.0 中使用的 GLSL 版本是 GLSL ES 1.0。 WebGL 2.0 中仍然可用。但是&#xff0c;通过编…...

[大模型实战] DAMODEL云算力平台部署LLama3.1大语言模型

[大模型实战] DAMODEL云算力平台部署LLama3.1大语言模型 目录 一、LLama3.1二、DAMODEL云算力平台2.1 提供的服务2.1.1 AI训练2.1.2 AI推理2.1.3 高性能计算2.1.4 图像&#xff0f;视频渲染2.1.5 定制化部署 2.2 支持的GPU 三、在DAMODEL部署LLama3.13.1 在DAMODEL创建实例&…...

驱动开发系列09 - Linux设备模型之设备,驱动和总线

一:概述 Linux 设备模型(LDM)是 Linux 内核中引入的一个概念。用于管理内核对象(那些需要引用计数的对象、例如文件、设备、总线甚至驱动程序),以及描述它们之间的层次结构,以及这些内核对象之间绑定关系。Linux 设备模型引入了对象生命周期管理、引用计数、以及面向对象…...

HTML实现弹出层

leopard/ˈlepərd/ 豹子&#xff0c;豹纹 弹出层指的是鼠标悬停于某个元素之上时显示的一个界面组件。 关注和理解特性&#xff1a;z-index属性和动态生成HTML元素。 HTML5新增&#xff1a; figure:媒体内容(图像&#xff0c;音频&#xff0c;视频)&#xff0c;用于包含一…...

Android控件详解

在Android应用程序中&#xff0c;界面由布局和组件组成。布局相当于框架&#xff0c;而控件则是框架里面的内容。了解过Android布局后&#xff0c;如果要设计ui界面&#xff0c;还需要了解和掌握各个控件的应用。 一个界面的设计&#xff0c;先从创建容器开始&#xff0c;再向…...

记忆化搜索专题篇

目录 斐波那契数 不同路径 最长递增子序列 猜数字大小II 矩阵中的最长递增路径 声明&#xff1a;下面将主要使用递归记忆化搜索来解决问题&#xff01;&#xff01;&#xff01; 斐波那契数 题目 思路 斐波那契数的特点就是除了第一个数是0&#xff0c;第二个数是1&…...

入网测评检查项大全(安全资料)

1. Linux操作系统 2. Windows操作系统 3. Tomcat中间件 4. Nginx中间件 5. Mysql数据库 6. Weblogic中间件 7. Oracle数据库 8. Redis数据库 9. 达梦数据库 10. 应用系统 11. 渗透测试 13 .AIX操作系统 14 .中创中间件 15 .IIS中间件 16 .Apache中间件 17 .Mari…...

uni-app 开发App时调用uni-push 实现在线系统消息推送通知 保姆教程

一、引言 在开发App时避免不了需要推送系统通知&#xff0c;以提高用户的使用体验。在自己的一个工具型的小app上全流程接入了uni-push2.0的推送能力&#xff0c;做个记录&#xff0c;以防后期需要用到。在阅读本教程前最好先看看官方文档&#xff0c;结合官方文档使用&#xf…...

13.StringRedisTemplete使用

上一篇说到改变了RedisTemplate的默认序列化器后&#xff0c;在redis中存入Java对象后&#xff0c;在redis中的呈现是&#xff1a;会记录类的字节码 这也是代码中可以强制装换为对应的java对象的原因&#xff1a; Test void testStudent() {redisTemplate.opsForValue().set(&q…...

[工具]-gitee+pycharm-配置

安装git ​ 查看git是否安装设置成功&#xff1a; ​ git config user.name ​ git config user.email ​ 码云账号设置邮箱 pycharm设置gitee 打开 PyCharm&#xff0c;在 Settings - Plugins 里面&#xff0c;搜索 Gitee 插件&#xff0c;安装后重启 PyCharm。 pychar…...

中间件是一种在客户端和服务器之间进行通信和处理的软件组件或服务

中间件是一种在客户端和服务器之间进行通信和处理的软件组件或服务。中间件位于应用程序和操作系统之间&#xff0c;可以提供一些功能&#xff0c;如请求转发、数据转换、安全性和身份验证、日志记录等。 中间件的主要作用是将应用程序与底层基础设施解耦&#xff0c;提供了一…...

RCE-eval长度限制突破技巧

目录 一、长度17的限制绕过 1、最简单的绕过 &#xff08;一&#xff09;绕过 &#xff08;二&#xff09;编写一句话木马 2、文件包含的利用 &#xff08;一&#xff09;远程文件包含的利用 &#xff08;二&#xff09;本地文件包含的利用 3、usort绕过 &#xff08…...

【黑马】MyBatis

目录 MyBatis简介JDBC缺点&#xff1a;MyBatis针对于JDBC进行简化&#xff0c;简化思路&#xff1a; MyBatis快速入门具体构建步骤解决SQL映射文件的警告提示 Mapper代理开发案例&#xff1a;使用Mapper代理方式完成案例具体步骤详解&#xff1a;Mapper代理方式 Mapper核心配置…...

oracle创建dblink使得数据库A能够访问数据库B表LMEAS_MFG_FM的数据

1、给数据库A普通用户CMRONLINE相应的权限&#xff0c;在sys用户下执行以下语句 GRANT CREATE DATABASE LINK TO CMRONLINE; GRANT DROP PUBLIC DATABASE LINK TO CMRONLINE; GRANT CREATE PUBLIC DATABASE LINK TO CMRONLINE; 2、在数据库A用户 CMRONLINE下执行创建语句&…...

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制&#xff0c;因此这个了16进制的数据既可以翻译成为这个机器码&#xff0c;也可以翻译成为这个国标码&#xff0c;所以这个时候很容易会出现这个歧义的情况&#xff1b; 因此&#xff0c;我们的这个国…...

苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会

在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...

k8s从入门到放弃之HPA控制器

k8s从入门到放弃之HPA控制器 Kubernetes中的Horizontal Pod Autoscaler (HPA)控制器是一种用于自动扩展部署、副本集或复制控制器中Pod数量的机制。它可以根据观察到的CPU利用率&#xff08;或其他自定义指标&#xff09;来调整这些对象的规模&#xff0c;从而帮助应用程序在负…...

C++ 类基础:封装、继承、多态与多线程模板实现

前言 C 是一门强大的面向对象编程语言&#xff0c;而类&#xff08;Class&#xff09;作为其核心特性之一&#xff0c;是理解和使用 C 的关键。本文将深入探讨 C 类的基本特性&#xff0c;包括封装、继承和多态&#xff0c;同时讨论类中的权限控制&#xff0c;并展示如何使用类…...

标注工具核心架构分析——主窗口的图像显示

&#x1f3d7;️ 标注工具核心架构分析 &#x1f4cb; 系统概述 主要有两个核心类&#xff0c;采用经典的 Scene-View 架构模式&#xff1a; &#x1f3af; 核心类结构 1. AnnotationScene (QGraphicsScene子类) 主要负责标注场景的管理和交互 &#x1f527; 关键函数&…...

Vuex:Vue.js 应用程序的状态管理模式

什么是Vuex&#xff1f; Vuex 是专门为 Vue.js 应用程序开发的状态管理模式 库。它采用集中式存储管理应用的所有组件的状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化。 在大型单页应用中&#xff0c;当多个组件共享状态时&#xff0c;简单的单向数据流…...

基于Java的离散数学题库系统设计与实现:附完整源码与论文

JAVASQL离散数学题库管理系统 一、系统概述 本系统采用Java Swing开发桌面应用&#xff0c;结合SQL Server数据库实现离散数学题库的高效管理。系统支持题型分类&#xff08;选择题、填空题、判断题等&#xff09;、难度分级、知识点关联&#xff0c;并提供智能组卷、在线测试…...

前端技能包

ES6 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body><script>// 变量定义var a1;let b5; // 现在使用let 定义变量// 对象解构let person{&quo…...

TM中,return new TransactionManagerImpl(raf, fc);为什么返回是new了一个新的实例

这是一个典型的 构造器注入 封装资源的用法 &#x1f9e9; 代码片段 return new TransactionManagerImpl(raf, fc);✅ 简单解释&#xff1a; 这行代码的意思是&#xff1a; 使用已经打开的 RandomAccessFile 和 FileChannel&#xff0c;创建并返回一个新的 TransactionManag…...

八:操作系统设备管理之缓冲、缓存与假脱机

弥合鸿沟&#xff1a;操作系统中的缓冲、缓存与假脱机技术深度解析 在计算机系统的世界里&#xff0c;存在着一个根本性的速度差异&#xff1a;中央处理器&#xff08;CPU&#xff09;的执行速度飞快&#xff0c;而输入/输出&#xff08;I/O&#xff09;设备&#xff08;如硬盘…...