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两种持久化方式。如果不需要持久化,或者可…...

JavaSec-RCE
简介 RCE(Remote Code Execution),可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景:Groovy代码注入 Groovy是一种基于JVM的动态语言,语法简洁,支持闭包、动态类型和Java互操作性,…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...

vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...

图表类系列各种样式PPT模版分享
图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...
Python Einops库:深度学习中的张量操作革命
Einops(爱因斯坦操作库)就像给张量操作戴上了一副"语义眼镜"——让你用人类能理解的方式告诉计算机如何操作多维数组。这个基于爱因斯坦求和约定的库,用类似自然语言的表达式替代了晦涩的API调用,彻底改变了深度学习工程…...
MySQL 部分重点知识篇
一、数据库对象 1. 主键 定义 :主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 :确保数据的完整性,便于数据的查询和管理。 示例 :在学生信息表中,学号可以作为主键ÿ…...