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

C++对象模型剖析(六)一一Data语义学(三)

Data 语义学(三)

“继承” 与 Data member

上期的这个继承的模块我们还剩下一个虚拟继承(virtual inheritance)没有讲,现在我们就来看看吧。

  • 虚拟继承(Virtual Inheritance)

    虚拟继承本质就是:通过某种形式来实现共享继承,使被继承的类在继承体系中只存在一个实例。最常用的就是:解决菱形继承。

    下面我们看一个熟悉的例子:

    在这里插入图片描述

    这样我们就能够很清楚的知道多重继承和虚拟继承的区别,而且我们也能看出在多重继承的体系下,我们需要维护两个 ios base class object ,这就造成了空间和效率上的浪费,我们不仅要为这两个 ios object 分配空间,我们还要同步对他们的修改操作,来保证两个 object 是一样的。所以,解决这个问题的关键就是导入虚拟继承(virtual inheritance)。

    class ios { ... }
    class istream : public virtual ios { ... }
    class ostream : public virtual ios { ... }
    class iostream : public istream, public ostream { ... }
    

    但是在编译器中实现虚拟继承难度很高:编译器需要一个足够有效的方法,将 istream 和 ostream 各自维护的一个 ios subobject,折叠成为一个由 iostream 维护的单一的 ios subobject,并且还可以保存 base class 和 derived class 的指针(以及 引用)之间的多态指定的操作。(polymorphism assignments)。

    一般的实现方法是这样的:**Class 如果内含一个或多个 virtual base class subobjects,像 istream 那样,将被分割成两部分,一个不变区域和一个共享区域。**不变区中的数据,不管后继如何衍化,总是拥有固定的 offset,所以这一部分数据可以被直接存取。至于共享区域,所表现的就是 virtual base class object。这一部分的数据,其位置会因为每一个的派生操作而发生变化,所以它们只可以被间接存取。各家编译器实现技术之间的差异就在于间接存取的方法不同。下面就为大家介绍这三种方法。

    首先看看Vertex3d虚拟继承的层次结构。

    class Point2d {
    public:...
    protected:float _x, _y;
    };class Vertex : public virtual Point2d {
    public:....
    protected:Vertex *next;
    };class Point3d : public virtual Point2d {
    public:...
    protected:float _z;
    };class Vertetx3d : public Vertex, public Point3d {
    public:...
    protected:float mumble;
    };// 继承关系
    //				Point2d(_x, _y)
    //				    |
    //				____|____
    //			    |        | 
    //		Vertex(next)	Point3d(_z)
    //		    	|        |
    //			    |________|
    //					|
    //				  Vertex3d(mumble)
    

    **一般的布局策略是先安排好 derived class 的不变部分,然后再建立其共享部分。**不同的编译器对 virtual inheritance 的实现的不同就体现在共享部分的实现上。

    • 第一个方法:在 derived class 种添加指向 virtual base class 的指针

      直接上书上的例子

      void Point3d::operator+=(const Point3d &rhs)
      {_x += rhs._x;_y += rhs._y;_z == rhs._z;
      };
      // 在这种策略下,这个运算符会被内部转换为
      _vbcPoint2d->_x += rhs._vbcPoint2d->_x;
      _vbcPoint2d->_y += rhs._vbcPoint2d->_y;
      _z += rhs._z;// 现在我们考虑另一种情况
      Point2d *p2d = pv3d;
      // 同样在这种策略下,这个转换也会被内部转换为
      Point2d *p2d = pv3d ? pv3d->_vbcPoint2d : 0;
      

      这个实现模型有两个主要的缺点:

      • 每一个对象必须针对其每一个 virtual base class 背负一个额外的指针。然而理想上我们却希望 class object 有固定的负担,不因为其 virtual base class 的个数而变化。
      • 由于虚拟继承串链的加长,导致间接存取层次的增加。这里的意思是,如果我有三层虚拟派生,我就需要三次间接存取(经由三个 virtual base class 指针)。然而理想上我们却希望有固定的存取时间,不因为虚拟派生的深度而改变。

      对于第二缺点,有些编译器会选择通过拷贝的操作取得所有的 nested virtual base class 指针,放到 derived class object 之中。这就解决了“固定存取时间”的问题,但是同时也付出一些空间上的代价。所以一般这些编译会提供一个选项——询问程序员是否要产生双重指针。

      看看模型的布局
      在这里插入图片描述

      对于第一个缺点,就引出了剩余的两个解决方案。

    • Microsoft 编译器引入了 virtual base class table。

      每一个class object 如果有一个或多个 virtual class table,就会由编译器安插一个指针,指向 virtual base class table。至于正真的 vitual base class pointer 将会被放在该表格中。

    • 在 virtual function table 中放置 virtual base class 的 offset(而不是地址)。

      以上面的继承体系为例,我们看看在这种策略下,每一个类(class)的布局

      image-20240302102506928

      上面的图很直观的呈现的这种将 virtual base class offset 和 virtual function table 结合的方法,virtual function table 可经由正值或负值来索引。如果是正值,很显然就是索引到了 virtual function table;如果是负值,则是索引到了 virtual base class offsets。

      // 再来看看这个 operator
      void Point3d::operator+=(const Point3d &rhs)
      {_x += rhs._x;_y += rhs._y;_z += rhs._z;
      }// 在这种策略下,编译器在内部做的转换如下
      void Point3d::operator+=(const Point3d &rhs)
      {(this + _vptr_Point3d[-1])->_x += (&rhs + rhs._vptr_Point3d[-1])->_x;(this + _vptr_Point3d[-1])->_y += (&rhs + rhs._vptr_Point3d[-1])->_y;_z += rhs._z;
      }// 转换操作
      Point2d *p2d = pv3d;
      Point3d *p2d = pv3d ? pv3d + pv3d->_vptr_Point3d[-1] : 0;
      

    上面的每一种方法都是一种实现模型,而不是一种标准。每一种模型都是用来解决 “存取 shared subobject 内的数据(其位置会因每次派生操作而变化)”所引发的问题。

    一般而言,virtual base class 最有效的运用形式就是:一个抽象的 virtual base class,没有任何 data member。

    也就是我们所说的抽象类,在该类中定义纯虚函数(pure virtual function),也称为接口(interface)。

    还有一小节讲的是类成员指针(data member pointer),但是有点奇怪的是实验的结果跟书上显式的不一样,这个等我弄明白了再更吧,如果你们知道为什么求求出个文章吧。

相关文章:

C++对象模型剖析(六)一一Data语义学(三)

Data 语义学(三) “继承” 与 Data member 上期的这个继承的模块我们还剩下一个虚拟继承(virtual inheritance)没有讲,现在我们就来看看吧。 虚拟继承(Virtual Inheritance) 虚拟继承本质就是…...

Java 代理模式详解(附案例源代码)

前言 Java代理模式是一种设计模式,在 Java 开发中被广泛应用。它允许我们通过添加一个代理对象来控制对另一个对象的访问,从而提供了一种间接访问实际对象的方法。 代理模式可以分为静态代理和动态代理两种。静态代理是在代码实现阶段就确定了代理…...

七牛云 上传 文件 file is empty

问题 七牛云 上传 文件 file is empty 详细问题 笔者进行Android 开发,使用URI上传文件,上传核心代码 具体报错信息 {ver:8.7.0,ResponseInfo:1709276329412131,status:-6, reqId:, xlog:null, xvia:null, host:null, time:1709276329,error:file is…...

【AI视野·今日Sound 声学论文速览 第五十二期】Tue, 5 Mar 2024

AI视野今日CS.Sound 声学论文速览 Tue, 5 Mar 2024 Totally 18 papers 👉上期速览✈更多精彩请移步主页 Daily Sound Papers SA-SOT: Speaker-Aware Serialized Output Training for Multi-Talker ASR Authors Zhiyun Fan, Linhao Dong, Jun Zhang, Lu Lu, Zejun M…...

使用 BLAS 调用加快生成的独立代码中的矩阵运算

为了提高某些低级向量生成的代码的执行速度,并 矩阵运算(如矩阵乘法)在独立代码中,指定您 要MATLAB Coder™生成 BLAS 调用。BLAS 是一个用于低级向量和矩阵计算的软件库,它具有 几个高度优化的机器特定实现。代码生成…...

一台服务器,最大支持的TCP连接数是多少?

一个服务端进程最大能支持多少条 TCP 连接? 一台服务器最大能支持多少条 TCP 连接? 一、原理 TCP 四元组的信息:源IP、源端口、目标IP、目标端口。 一个服务端进程最大能支持的 TCP 连接个数的计算公式:最大tcp连接数客户端的IP…...

微信小程序云开发教程——墨刀原型工具入门(编辑页面)

引言 作为一个小白,小北要怎么在短时间内快速学会微信小程序原型设计? “时间紧,任务重”,这意味着学习时必须把握微信小程序原型设计中的重点、难点,而非面面俱到。 要在短时间内理解、掌握一个工具的使用&#xf…...

flutter打包app

Flutter 打包APP (Android & IOS)_encountered error while building for device.-CSDN博客 使用命令行 keytool -genkey -v -keystore ../key -keyalg RSA -keysize 2048 -validity 10000 -alias key 将在文件根目录上一层生成key文件&#xff0…...

力扣543. 二叉树的直径

Problem: 543. 二叉树的直径 文章目录 题目描述思路复杂度Code 题目描述 思路 1.最大直径 左子树的最大深度 右子树的最大深度; 2.定义一个变量maxDiameter记录最大直径,并编写一个递归函数maxDepth,利用树的后序遍历每次递归求取leftMax&a…...

python网络爬虫教程笔记(1)

系列文章目录 文章目录 系列文章目录前言一、爬虫入门1.爬虫是什么?2.爬虫工作原理3.爬虫基本原理4.工作流程5.HTTP请求6.HTTP响应7.HTTP原理:证书传递、验证和数据加密、解密过程解析8.Urllib.request库的使用9.TCP3次握手,4次挥手过程 总结…...

C# 异步返回类型详解

在现代软件开发中,异步编程已经成为一种重要的编程范式,尤其是在需要与I/O密集型操作交互的上下文中,比如网络请求、数据库操作等。C# 语言提供了强大的异步支持,使得异步编程变得更加简单和直观。本文将详细介绍C#中异步返回类型…...

BAT等大厂必问技术面试题,【2024Android最新学习路线

下面分享一下我在爱奇艺的面经 面试前的话:在面试时一定不要受前面没有过的面试的影响,一定要有一个好的心态,不要面试还没开始就自己把自己思绪搞乱了 一共进行了4轮面试 爱奇艺一面 50min 项目 主要介绍了以前做过的项目,分析…...

72. 编辑距离【leetcode】/动态规划难

72. 编辑距离 给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数 。 你可以对一个单词进行如下三种操作: 插入一个字符删除一个字符替换一个字符 示例 1: 输入:word1 “horse”, word2 “ros”…...

【MySQL】视图、索引

目录 视图视图的用途优点视图的缺点创建视图查看视图修改视图删除视图注意事项 索引索引的原理索引的数据结构二分查找法Hash结构Hash冲突!!! B树二叉查找树 存在问题改造二叉树——B树降低树的高度 B树特点案例继续优化的方向 改造B树——B树…...

反编译java生成的.class文件

java代码编译后生成xxx.class文件,有时候需要反编译这个class文件看代码是怎么写的,可以使用下面这个工具。 工具已经上传到资源,链接: https://download.csdn.net/download/weixin_42556307/88915887 具体使用如下: …...

Cookie 探秘:了解 Web 浏览器中的小甜饼

🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…...

Python线性代数数字图像和小波分析之二

要点 数学方程:数字信号和傅里叶分析,离散时间滤波器,小波分析Python代码实现及应用变换过程: 读取音频和处理音频波,使用Karplus-强算法制作吉他音频离散傅里叶计算功能和绘制图示结果计算波形傅里叶系数正向和反向&…...

LC.exe”已退出,代码为 -1

尽管网络上已经有许多详尽的说明和资料,但鉴于个人对大量文字的理解有反感,我就写一个更为直观、简洁的方式来呈现我的解决方案。 1.问题图片。 2.删除licenses.licx 3.问题解决...

springboot + jpa + 达梦数据库兼容 Mysql的GenerationType.IDENTITY主键生成策略

导入达梦数据库对hibernate的方言包 <dependency><groupId>com.dameng</groupId><artifactId>DmDialect-for-hibernate5.6</artifactId><version>8.1.2.192</version></dependency>配置文件中添加方言配置和主键生成策略配置…...

Redis优化与应用

Redis性能调优 - Redis的性能调优是一个比较复杂的过程&#xff0c;需要从多个方面进行优化&#xff0c;如内存使用、命令使用等。 - 案例&#xff1a;减少不必要的持久化操作。默认情况下&#xff0c;Redis会执行RDB和AOF两种持久化方式。如果不需要持久化&#xff0c;或者可…...

深入了解Kafka的文件存储原理

Kafka简介 Kafka最初由Linkedin公司开发的分布式、分区的、多副本的、多订阅者的消息系统。它提供了类似于JMS的特性&#xff0c;但是在设计实现上完全不同&#xff0c;此外它并不是JMS规范的实现。kafka对消息保存是根据Topic进行归类&#xff0c;发送消息者称为Producer&…...

RabbitMQ 高级

在昨天的练习作业中&#xff0c;我们改造了余额支付功能&#xff0c;在支付成功后利用RabbitMQ通知交易服务&#xff0c;更新业务订单状态为已支付。 但是大家思考一下&#xff0c;如果这里MQ通知失败&#xff0c;支付服务中支付流水显示支付成功&#xff0c;而交易服务中的订单…...

音视频开发之旅——音频基础概念、交叉编译原理和实践(LAME的交叉编译)(Android)

本文主要讲解的是音频基础概念、交叉编译原理和实践&#xff08;LAME的交叉编译&#xff09;&#xff0c;是基于Android平台&#xff0c;示例代码如下所示&#xff1a; AndroidAudioDemo 音频基础概念 在进行音频开发的之前&#xff0c;了解声学的基础还是很有必要的。 声音…...

直播美颜SDK开发指南:构建个性化的主播美颜工具

本篇文章&#xff0c;小编将带您深入了解如何构建个性化的主播美颜工具&#xff0c;从而为用户提供更优质的直播体验。 一、美颜技术概述 在开始SDK的开发之前&#xff0c;我们首先需要了解美颜技术的基本原理。美颜技术通常包括肤色检测、人脸检测、特征点定位、滤镜处理等步…...

羊大师揭秘,羊奶有哪些好处和不足呢?

羊大师揭秘&#xff0c;羊奶有哪些好处和不足呢&#xff1f; 羊奶的好处主要包括&#xff1a; 营养丰富&#xff1a;羊奶中含有多种人体所需的营养成分&#xff0c;如蛋白质、脂肪、碳水化合物、矿物质和维生素等。尤其是蛋白质含量高&#xff0c;且易于人体吸收利用。 增强免…...

鸿蒙问题之CustomDialog后持久化@state数据崩溃

开发需求&#xff1a;有一个字符串数组&#xff0c;可以通过弹框编辑其中的某个字符串&#xff0c;编辑完成后更新数组并持久化这个数组。 这个需求算是很简单&#xff0c;很常见的需求了。但是&#xff0c;开发过程中却遇到了一个不小的难题。 我的数组内容需要在组件中显示…...

微服务高性能通信技术-gRPC实战落地

在微服务架构中&#xff0c;服务之间的通信是至关重要的。为了实现高性能、低延迟和跨语言的服务间通信&#xff0c;gRPC是一个流行的选择。gRPC是一个开源的、高性能的、通用的RPC&#xff08;远程过程调用&#xff09;框架&#xff0c;基于HTTP/2协议和Protocol Buffers序列化…...

洛阳旅游攻略

洛阳旅游攻略 第一天&#xff08;抵达当天&#xff09;&#xff1a; 1.先将行李放到酒店—2.老城十字街&#xff08;打车可能会堵车&#xff09;—3.洛邑古城—4.丽景门&#xff08;步行&#xff09; 第二天&#xff1a; 1.早起吃早餐—&#xff08;打车三十分钟&#xff0c…...

图论例题解析

1.图论基础概念 概念 &#xff08;注意连通非连通情况&#xff0c;1节点&#xff09; 无向图&#xff1a; 度是边的两倍&#xff08;没有入度和出度的概念&#xff09; 1.完全图&#xff1a; 假设一个图有n个节点&#xff0c;那么任意两个节点都有边则为完全图 2.连通图&…...

图解 TCP 拥塞控制

文章目录 什么是拥塞控制拥塞控制算法慢启动拥塞避免快速恢复 TCP拥塞控制状态机 什么是拥塞控制 拥塞控制是一种 确保网络中的数据包以可持续的速率传输 的机制&#xff0c;避免因为数据包太多而超过网络当前的承载能力&#xff0c;导致网络性能下降&#xff0c;甚至产生大量…...