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)的布局
上面的图很直观的呈现的这种将 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…...
微信小程序云开发教程——墨刀原型工具入门(编辑页面)
引言 作为一个小白,小北要怎么在短时间内快速学会微信小程序原型设计? “时间紧,任务重”,这意味着学习时必须把握微信小程序原型设计中的重点、难点,而非面面俱到。 要在短时间内理解、掌握一个工具的使用…...
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文件࿰…...
力扣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的性能调优是一个比较复杂的过程,需要从多个方面进行优化,如内存使用、命令使用等。 - 案例:减少不必要的持久化操作。默认情况下,Redis会执行RDB和AOF两种持久化方式。如果不需要持久化,或者可…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...
STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...
springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
STM32HAL库USART源代码解析及应用
STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...
关于easyexcel动态下拉选问题处理
前些日子突然碰到一个问题,说是客户的导入文件模版想支持部分导入内容的下拉选,于是我就找了easyexcel官网寻找解决方案,并没有找到合适的方案,没办法只能自己动手并分享出来,针对Java生成Excel下拉菜单时因选项过多导…...
【堆垛策略】设计方法
堆垛策略的设计是积木堆叠系统的核心,直接影响堆叠的稳定性、效率和容错能力。以下是分层次的堆垛策略设计方法,涵盖基础规则、优化算法和容错机制: 1. 基础堆垛规则 (1) 物理稳定性优先 重心原则: 大尺寸/重量积木在下…...
