C++11:继承

news2024/11/27 12:00:54

目录

继承的基本概念

继承方式

 基类和派生类对象赋值转换/切片

继承中的作用域

派生类的四个成员函数:

 构造函数

拷贝构造函数

赋值重载

析构函数

静态成员

继承与友元

多继承

菱形继承

多继承的指针偏移问题

 组合


继承的基本概念

继承出现的契机是某一些类中会有一部分相似的信息,我们希望以这个类的基本信息为基础能生成更多高分化的类。

集体来讲就是具有一些公共属性的类我们不希望多次去写,比如说人们的职位分布,其主要重合的信息比如名字电话号码性别等等

具体的操作流程如下,我们创建一个叫Person的类,然后使用public的继承方式将其继承到worker这个子类上

当然继承的术语还有其他叫法,不过都一样,喜欢哪个用哪个

继承的使用格式:

 子类会会继承获得父类的成员变量以及成员函数

好,既然牵扯到了访问限定符的问题,那么对于子类,它的访问方式是怎么做的呢?或者说它的访问规则是怎么样的?

继承方式

 

由于访问限定符和继承方式33相乘,有9种继承方式,不过说明白还是比较简单的

基类中的私有其本意是:“我不想给你继承”,我们调试看看

  • 诶?不对啊,不是说不可见吗,这不还是继承下来了吗?这里造成误解的原因则是关于“不可见”的定义问题,虽然private修饰的成员变量是不可见的,但此处的不可见则是指于子类中,无论是类内部还是外部都不能访问这个继承下来的变量。继承是继承下来了,但是它上了层盾,你没法访问。

但是这里还是很奇怪,我为什么还是能借助父类的函数访问到不可见的变量?

 这里的做法确实没有什么问题,但是如果我们想在子类去访问就不行了。

那么有没有比较中立一点的?protect就可以实现比private宽容一点的访问权限,也就是类外部依旧不能访问,但是类内部可以。

我们在protect下创建一个新的成员变量,然后在派生类的成员函数中去访问它。

那么上面的情况都是在public的条件下派生类继承基类时的权限问题,那么当我们更换继承方式的时候是什么样的?

当我们使用Protect的方式访问时,位于public下的函数不能使用了,但是protect内部的依然可以private依旧不行

由于重复内容比较多,就借用一下表格了。

总结起来:

  • 当以public方式继承时,子类可以访问到父类public下的成员函数以及成员变量,也可以访问到portected下的变量和函数,private不行。
  • 当以protected方式继承时,子类不能访问到父类访public下的成员函数以及成员变量,但可以访问到portected下的变量和函数,private不行。
  • 当以protected方式继承时,子类不能访问到父类访public下的成员函数以及成员变量,依然可以访问到portected下的变量和函数,private不行。

需要注意的是:访问限定符可以不写

使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式

在实际运用中一般使用都是public继承,几乎很少使用protetced/private继承,也不提倡使用protetced/private继承,因为protetced/private继承下来的成员都只能在派生类的类里面使用,实际中扩展维护性不强

 总结继承的实用性:继承的这个复用功能如果去细品会发现它还是能节省不少工作流程的,我们仅需要一个主体框架,当我们需要以这个框架为基础生成更加多功能的组件或者说类的时候,复用就会变得方便许多,毕竟我们不需要再回头去改类内部的成员变量函数什么的。

 基类和派生类对象赋值转换/切片

 既然使用了继承,那么子类一般情况下一定会比父类多一点成员变量什么的,在这种情况下假如将子类赋值回给父类生成的对象,父类的引用,父类的指针时,就会产生一个类似切片的过程

 非常形象,子类对象反赋值回父类对象直接将子类对象中多余的部分切去,保留对应的父类成员变量。

注意!在这个过程中没有类型转换!也没有临时对象,根据我们之前学习的内容,两个不同类型的类是不能相互赋值的,能发生类型转换的是单参构造函数虽然可以发生,在这个过程中,单一变量被拿去构造了一个相同类型的临时对象,这个临时对象去赋值给新的对象。

而且仅针对子类向上赋值给父类,不能父类给子类。

所以这个赋值的过程是不会生成临时变量的。

那么看上去也没什么影响嘛!不就是少了个临时对象么?

临时对象其实在很多方面会比较碍事,比如如下,我们想引用一下这个j,但是其中产生的临时变量具有常性,所以不行,加个const才行。

举个例子:

 而父类子类这个过程就不需要考虑了,直接爽用

但是也是有代价的,赋值或者引用发生时,它仅生效于父类子类相同的那一部分

而且继承赋值时,会调用父类的拷贝构造函数

继承中的作用域

 有个小问题,当我们的子类和父类中都有一个同名的变量时,访问哪一个?

在子类访问用子类的,父类访问用父类的

当然想要在子类访问父类的也不是不行,加个作用于限定符即可。

其实发生这种现象的原因是当出现同名对象时,子类会隐藏父类的同名成员,但不是不让访问

那么刚才是同名的成员变量,那么假如现在是同名成员函数会怎么处理?

首先一定会触发隐藏,跟同名的成员变量没什么区别。

但是如果它写成重载的样式呢??刁钻的老6就来了。

那么它们构成重载还是重写呢?还是隐藏(重定义)或者编译报错?

  • 首先,重载的发生条件是处于同一作用域下才会重载。
  • 那么他就不是能重载的,如下这样使用时就是单纯的隐藏。

 以函数调用为举证,当前的Text需要传参

 构成了隐藏,没法调到A的函数,被隐藏了要加作用域限定符才是。

派生类的四个成员函数:

 既然派生类类会继承基类的对象,那么它里面的各个成员函数的工作则是不同的。

 构造函数

  • 不同于我们创建一个新的对象,对于派生类来说,基类的对象派生类只能去调用基类的构造函数才能初始化,同理,假如基类对象其中有需要被清理的资源也只能调用父类的析构函数
  • 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认
  • 的构造函数,则必须在派生类构造函数的初始化列表阶段显示调用。

我们就尝试初始化一下基类的对象

  •  但是想要去初始化它是不可以通过直接访问的方式来进行的,要调用基类的构造函数才行。

 调用父类的构造函数

拷贝构造函数

  •  拷贝构造也是同理,基类的对象需要调用基类的拷贝构造来拷贝,派生类的则是处理自己的对象。派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化
     

 当然,我们也可以借助切片的行为来实现拷贝构造,切片的行为会自己调用父类的拷贝构造函数。

赋值重载

子类的和父类构成隐藏,派生类的operator=必须要调用基类的operator=完成基类的复制

析构函数

已我们前面的理解,既然构造等默认成员函数们都是以各自管各自类的工作方法执行它们的功能,那么析构函数也应该是子类析构自己的,然后调用父类的析构去析构父类成员。

但是析构函数有个让人不解的点:为什么没办法调用父类的构造?

 这样就可以了

 

 为什么加了个作用域就可以了?

  • 因为子类析构函数和父类析构函数构成了隐藏关系(由于后面多态的关系需求,所有的析构函数都会被特殊处理成为相同名字的函数,然后构成隐藏)

但是还有一个及其奇怪的点,为什么我们在指定作用域只调用了一次父类的析构函数,结果调用了两次父类的析构函数?甚至还崩溃了。

继承结构下的析构函数的特点:因为子类的析构函数会自己默认调用父类的析构函数

  • 子类的析构函数和父类的析构函数默认情况下会构成隐藏关系,从调用角度来讲,我们没法直接调用到基类的析构函数来析构基类的对象。(回顾一下:函数名相同时构成隐藏)但这根本名字不一样啊?原因就是为了多态而服务的,因为后续一些场景析构函数需要构成重写,重写的条件之一是函数名相同。那么编译器会对析构函数名进行特殊处理,处理成destrutor(),所以父类析构函数不加virtual的情况下,子类析构函数和父类析构函数构成隐藏关系,这个问题要先遗留上一阵子了。

所以总结一下,子类的默认成员函数,构造和赋值都要显示调用,而析构则不用


做个小题目巩固以下知识吧!

下面说法正确的是( )

A.派生类构造函数初始化列表的位置必须显式调用基类的构造函数,已完成基类部分成员的初始化

B.派生类构造函数先初始化子类成员,再初始化基类成员

C.派生类析构函数不会自动析构基类部分成员

D.子类构造函数的定义有时需要参考基类构造函数

 


答案以及解析:

A.如果父类有默认构造函数,此时就不需要

B.顺序相反,先初始化父类,再是子类

C.会调用,并且按照构造的相反顺序进行调用

D.是的,需要看父类构造函数是否需要参数子类的,从而你决定子类构造函数的定义

静态成员

  • 当继承发生时,其静态成员还是同一个,而非静态成员则是各自的。
  • 究其原因,静态成员是属于整个类中所有的对象,同时也属于所有的派生类。

继承与友元

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

多继承

在继承的方法后面加上一个逗号就可以实现多继承

 

 比如说一个市民,它可以复用一个人类,然后再复用一个工人类,这其实还不错,但是非常阴间的玩意马上就来了,菱形继承

菱形继承

 

 

菱形继承会造成数据冗余以及二义性

  • 以二义性为例:以上的这个例子,相当于不仅继承了strudent的Person类,又继承了Teacher的Person类,假如我们直接去访问基类中的对象时,会直接报错,因为编译器也不知道你想访问那个Person类里头的对象。

我们构建一个简单的菱形继承,然后在内存中观察一下它真实的空间分配

 

 

  • 我们在内存之中看到了菱形继承的大致模型,这个模型本身并不复杂,而且非常直观,BC两个对象之中都各有一个a成员,他们是各自独立开来的。
  • 那么当我不想要独立开这个a的时候该怎么办呢?接下来的情况就有些复杂,我们对中介类加上一个virtual

 

  • 我们发现,a此时没有独立开来,而是算作了整个菱形继承的公共对象,无论在哪更改a,都指向了单独的一个a,而非独立开来的a。
  • 那么问题来了,原本的a的地址变成了什么?

 我们发现在内存中他们的字节数都是一样的,这个其实就是距离虚基类对象的偏移量

 这种记载偏移量的方法可以直接让我们使用菱形继承的时候编译器可以非常精确的寻找到当前基对象的位置并更改以解决二义性的问题。

多继承的指针偏移问题

多继承时,一个继承了多个类的对象在使用其中一个父类指针产生切片时,可能会发生指针偏移

借助一道题可以很好的理解这个问题

 那么P1 P2 的指向模型如下

 

 组合

 什么是组合?

 以上图为例,就是在一个类里面已某个自定义类型再创建了一个对象

  • 他和继承都是可以实现复用的,但是相较于继承,组合不能使用父类被保护的成员,
  • 那么有人提出了一个概念,继承称之为:白箱复用,而组合则叫做:黑箱复用
  • 黑和白的区别主要还是区别于能不能看见其中一些内部的使用方法。
  • 平常来讲,组合的效果会更加好,因为黑箱复用的耦合度较低。
  • 耦合度指的是关联互相影响度,牵连的东西的多少。
  • 我们以继承为例,由于是白箱复用,当我们更改父类内部的成员时,其子类绝对会受到影响,而对于组合来说则不会,毕竟没有对你门洞大开,其耦合度低,基本上影响不到组合的对象。

 

以上就是C++继承中部分的知识了

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

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

相关文章

Java 多线程 --- 锁的概念和类型划分

Java 多线程 --- 锁的概念和类型划分锁的概念乐观锁与悲观锁公平锁与非公平锁什么是可重入锁独占锁与共享锁轻量级锁和重量级锁自旋锁 (Spinlock)锁的概念 锁可以将多个线程对共享数据的并发访问转换为串行访问, 这样一个共享数据一次只能被一个线程访问, 该线程访问结束后其他…

cocos2dx+lua学习笔记:UIPageView的使用

前言 本篇在讲什么 本篇简单介绍Lua篇cocos2dx中UIPageView的相关内容 仅介绍简单的应用,仅供参考 本篇适合什么 适合初学Cocos2dX的小白 适合想要在Cocos2dx-lua中使用UIPageView的人 本篇需要什么 对Lua语法有简单认知 对Cocos2dx-Lua有简单认知 Cocos2…

Hostease美国Linux主机方案租用推荐

美国Linux主机市场在全球市场上具有显著的优势,这使得美国的主机提供商可以提供高性能、高可靠性和高安全性的主机方案,同时为用户提供广泛的选择和灵活性。这些优势也使得美国成为全球最大的主机市场之一。本文将介绍Hostease的美国Linux主机方案租用推…

22《Protein Actions Principles and Modeling》-《蛋白质作用原理和建模》中文分享

​《Protein Actions Principles and Modeling》-《蛋白质作用原理和建模》 本人能力有限,如果错误欢迎批评指正。 第五章:Folding and Aggregation Are Cooperative Transitions (折叠和聚合是同时进行的) -蛋白质折叠的协同作…

基于C/C++获取电脑网卡的IP地址信息

目录 前言 一、网卡是什么? 二、实现访问网卡信息 1.引入库及相关的头文件 2.操作网卡数据 3. 完整代码实现 4.结果验证 总结 前言 简单示例如何在windows下使用c/c代码实现 ipconfig/all 指令 提示:以下是本篇文章正文内容,下面案例可供参考…

【Python】Python项目打包发布(四)(基于Nuitka打包PySide6项目)

Python项目打包发布汇总 【Python】Python项目打包发布(一)(基于Pyinstaller打包多目录项目) 【Python】Python项目打包发布(二)(基于Pyinstaller打包PyWebIO项目) 【Python】Pytho…

【机器学习】决策树(理论)

决策树(理论) 目录一、何为决策树1、决策树的组成2、决策树的构建二、熵1、熵的作用2、熵的定义3、熵的计算4、条件熵的引入5、条件熵的计算三、划分选择1、信息增益( ID3 算法选用的评估标准)2、信息增益率( C4.5 算法…

使用ARM嵌入式工控机构建Node-RED应用的优势

Node-RED是一个基于Node.js的开源可视化流程编程环境,可以轻松构建自定义应用程序,通过连接简单的节点来完成复杂的任务。Node-RED提供了一种简单的方法,可以快速连接到外部服务,从而实现物联网应用的开发。 Node-RED的优点包括&…

工作实战之微服务认证实现

目录 前言 一、钻石段位springsecurityspringsessionredis缓存 1.yml配置将session存储到redis中,实现session共享 2.maven引入 3.原理分析 a.SessionRepositoryFilter拦截进行session存储介质的选择,可以是jdk缓存,或者数据库,也…

Leedcode 二分查找 理解1

一个up的理解 一、二分查找基础例题 力扣https://leetcode.cn/problems/binary-search/ 二、二分查找模板问题 带搜索区间分为3个部分: 1、[mid],直接返回 2、[left,mid-1],设置边界right mid - 1 3、[mid1,right]&#x…

【相关分析-高阶绘图】MATLAB实现皮尔逊相关分析-散点直方图

虽然皮尔逊相关分析很常见,但如何更好的展现相关性、散点分布、柱状分布,以提升研究结果的美感和冲击感呢?本文拟通过MATLAB绘制包含散点分布、柱状分布、线性展示的散点直方图,有助于审稿人眼前一亮。 1、Pearson相关系数原理 Pearson相关系数(Pearson Correlation Co…

Zookeeper3.5.7版本——单机部署(linux环境-centos7)

目录一、Zookeeper3.5.7官网下载1.1、官网下载地址1.2、下载步骤二、jdk11安装(Zookeeper需要jdk支持)三、Zookeeper3.5.7安装3.1、安装3.2、配置修改3.3、操作 Zookeeper四、配置文件参数解读一、Zookeeper3.5.7官网下载 1.1、官网下载地址 官网下载地…

基本面向对象编程-计算机基本功能实现_

《C/S项目实训》实验报告 实验名称: 基本面向对象编程-计算机基本功能实现_ 一、实验目的 通过综合实践项目,理解Java 程序设计是如何体现面向对象编程基本思想,掌握OOP方法,掌握事件触发、消息响应机制。进一步巩固面向对…

T_SQL和SQL的区别

一. SQL Server和T-SQL的区别(⭐T-SQL 包含了 SQL)SQL Server是结构化查询语言,是目前关系型数据库管理系统中使用最广泛的查询语言T-SQL是标准SQL语言的扩展,是SQL Server的核心,在SQL的的基础上添加了变量,运算符,函数和流程控制等,Microso…

AutoCAD通过handle id选择实体

获得实体的handle id。注意是handle id 不是id,方法有2种:方法(a):通过ArxDeg插件(ObjectARX附带的源码编译得到:\samples\database\ARXDBG)查找:此handle id本来就是16进…

【知识图谱论文】知识图谱嵌入的对比学习

文章题目: KGE-CL: Contrastive Learning of Knowledge Graph Embeddings时间:2021 摘要 学习知识图的嵌入在人工智能中至关重要,可以使各种下游应用受益,如推荐和问答。近年来,人们对知识图嵌入进行了大量的研究。然…

linux下安装java

文章目录linux下安装java1.下载对应的linux JDK包,这里使用jdk82.上传 jdk-8-linux-x64.tar.gz 到linux3.解压下载的jdk4.编辑配置文件,配置环境变量5.刷新配置文件6.最后检查JDK安装是否成功linux下安装java 阿里云弄的服务器centos7没有安装java&…

显示接口测试

背景需求两个显示器连接到一台PC,期望每台显示器可以单独显示,在一台显示器显示时,另外一台显示器同PC的连接断开,即系统下查看到连接状态为disconnected。同时在显示器上图形化显示当前显示器编号。如下图,期望当显示…

【pygame游戏】Python实现蔡徐坤大战篮球游戏【附源码】

前言 话说在前面,我不是小黑子~😏 本文章纯属技术交流~娱乐 前几天我获得了一个坤坤打篮球的游戏,也给大家分享一下吧~ 好吧,其实并不是这样的游戏,往下慢慢看吧。 准备工作 开发环境 Python版本:3.7.8 …

PhotoShop基础使用

49:图片分类 1:像素图 特点:放大后可见,右一个个色块(像素)组合而成。 优点:容量小,纯天然 JPG、JPEG、png、GIF 2:矢量图 面向对象图像 绘图图像 特点:不…