85 C++对象模型探索。数据语义学 - 继承多个类,且是虚基类的数据内存模型分析。虚基类表,虚基类表指针

news2024/11/18 10:19:13

前面我们分析了 继承多个类的情况。上一次分析的这样的情况:

今天看虚基类。先复习一下虚基类:类似下面这样的图

复习虚基类可以解决的问题:

在这之前先要复习一下多继承同一个爷爷类时带来的问题

空间问题

效率问题

二义性问题

//虚基类问题分析
class Teacher14Grand {
public:
	int grandage;
};

class Teacher14Father1 :public Teacher14Grand{

};

class Teacher14Father2 :public Teacher14Grand {

};

class Teacher14 :public Teacher14Father1, public Teacher14Father2 {

};

void main() {
	cout << sizeof(Teacher14Grand) << endl; //4
	cout << sizeof(Teacher14Father1) << endl; //4
	cout << sizeof(Teacher14Father2) << endl; //4
	cout << sizeof(Teacher14) << endl; //8
	//从上述结果可以看到,Teacher14的大小是8。这个大小是8,应该是从Teacher14Fathrer1继承了4个字节,从Teacher14Fathrer2继承了4个字节
	
	//问题:二义性问题,因为Teacher14有的内存布局中是 继承了Teacher14Father1的4个字节,继承了Teacher14Father2的4个字节
	//且Teacher14Father1的4个字节是从Teacher14Grand继承的 int grandage
	//且Teacher14Father2的4个字节是从Teacher14Grand继承的 int grandage
	//因此当我们使用Teacher14的对象 tea给grandage赋值的时候,编译器不知道是给Teacher14Father1中的grandage赋值,还是给Teacher14Father2中的grandage赋值,这个就是二义性问题的原因
	Teacher14 tea;
	//tea.grandage = 80;//像这样写就是有问题的,编译器不知道给那个grandage赋值。
	//fix方案,指定给那个具体的赋值
	tea.Teacher14Father1::grandage = 90;

	//当然,访问的时候,也要指定的访问那一个grandage
	cout << tea.Teacher14Father1::grandage << endl;

	//最开始猜想:由于tea.Teacher14Father2::grandage没有赋过值,因此这个值是乱码
	//但是实际上写这一行的时候,会有build error。提示“使用了未初始化的局部变量tea”
	//cout << tea.Teacher14Father2::grandage << endl;

二义性问题引申:

    //写到这里的时候,进而会想到一个问题。如果子类有和父类同名的变量,在这种case下,会不会也覆盖呢?

class Teacher15Grand {
public:
	int grandage = 80;
};

class Teacher15Father1 :public Teacher15Grand {
public:
	int grandage;
};

class Teacher15Father2 :public Teacher15Grand {

};

class Teacher15 :public Teacher15Father1, public Teacher15Father2 {

};


	//写到这里的时候,进而会想到一个问题。如果子类有和父类同名的变量,在这种case下,会不会也覆盖呢?
	//我们在Teacher15中验证一下。注意:这里不同的是在 Teacher15Grand 中有给grandage初始值为88
	cout << sizeof(Teacher15Grand) << endl; //4
	cout << sizeof(Teacher15Father1) << endl;//8,说明,还是会继承Teacher15Grand中的grandage,然后还有自己的grandage,一共占用8个字节
	cout << sizeof(Teacher15Father2) << endl;//4
	cout << sizeof(Teacher15) << endl;//12

	//那么又有一个问题了,怎么去访问这3个有效的成员呢?
	Teacher15 tea15;
	tea15.Teacher15Father1::grandage = 99; //对于 Teacher15Father1的grandage进行赋值
	tea15.Teacher15Father1::Teacher15Grand::grandage = 199;//对于
	tea15.Teacher15Father2::grandage = 299;

	cout << tea15.Teacher15Father1::grandage << endl;
	cout << tea15.Teacher15Father1::Teacher15Grand::grandage << endl;
	cout << tea15.Teacher15Father2::grandage << endl;

debug代码得到内存图

因此我们可以画出来Teacher14的 内存图

复习虚基类可以解决的问题:

继承爷爷的类使用 virtual 继承即可

class Teacher16Grand {
public:
	int grandage;
};

//让中间类虚继承爷爷
class Teacher16Father1 :public virtual Teacher16Grand {

};

//让中间类虚继承爷爷
class Teacher16Father2 :public virtual Teacher16Grand {

};

class Teacher16 :public Teacher16Father1, public Teacher16Father2 {

};

void main() {
	cout << sizeof(Teacher16Grand) << endl; //4
	cout << sizeof(Teacher16Father1) << endl; //8
	cout << sizeof(Teacher16Father2) << endl; //8
	cout << sizeof(Teacher16) << endl; //12
	//从上面的看到,Teacher16Fa;ther1 和 Teacher16Father2都多了4个字节。
	//这个四个字节是什么呢? 是虚基类表指针

	//引入两个概念 虚基类表,虚基类表指针
	//	只要有虚基类,就会有虚基类表 vbtable-- - virtual base table
	//	如果有子类的对象生成,就会有虚基类表指针 vbptr  virtual base table pointer

	Teacher16 tea;
	tea.grandage = 8;

	cout << "断点在这里" << endl;

}

使用2017开发人员命令试一下:

引出虚基类表,虚基类表指针 概念

只要有虚基类,就会有虚基类表 vbtable --- virtual base table

如果有子类的对象生成,就会有虚基类表指针 vbptr  virtual base table pointer

注意和 虚函数表 和 虚函数指针区分  vtable (virtual table) ,  vptr 也叫做vfptr (virtual  table pointer)

有虚基类和虚函数的同时存在时候 的内存图

内存图中先存储虚基类指针,然后再存储虚函数指针

class Teacher17Grand {
public:
	int grandage;

public:
	void virtual grandfunc() {

	}
};

//让中间类虚继承爷爷
class Teacher17Father1 :public virtual Teacher17Grand {

};

//让中间类虚继承爷爷
class Teacher17Father2 :public virtual Teacher17Grand {

};

class Teacher17 :public Teacher17Father1, public Teacher17Father2 {

};

void main() {
	//那么当既有虚基类表,也有虚函数表的时候,虚基类指针 和虚函数表指针那个放在前面呢?
	cout << sizeof(Teacher17Grand) << endl; //8
	cout << sizeof(Teacher17Father1) << endl; //12
	cout << sizeof(Teacher17Father2) << endl; //12
	cout << sizeof(Teacher17) << endl; //16

	Teacher17 tea;
	tea.grandage = 8;

	cout << "断点在这里" << endl;

}

当虚基类,虚函数,爷爷类,父亲类,子类都有成员变量的时候

class Teacher17Grand {
public:
	int grandage;

public:
	void virtual grandfunc() {

	}
};

//让中间类虚继承爷爷
class Teacher17Father1 :public virtual Teacher17Grand {
public:
	int father1age;
};

//让中间类虚继承爷爷
class Teacher17Father2 :public virtual Teacher17Grand {
public:
	int father2age;
};

class Teacher17 :public Teacher17Father1, public Teacher17Father2 {
public:
	int teaage;
};

void main() {
	//我们接着看,这些成员变量的值都是在哪里存储着?
	cout << sizeof(Teacher17Grand) << endl; // 8  一个vptr+ 一个int
	cout << sizeof(Teacher17Father1) << endl; // 16 一个vbptr  + 一个自己int + 一个vptr + 一个父类 int
	cout << sizeof(Teacher17Father2) << endl; // 16 一个vbptr  + 一个自己int + 一个vptr + 一个父类 int
	cout << sizeof(Teacher17) << endl; // 28 father1vbptr + father1age + father2vbptr + father2age +自己int + 爷爷vptr + 爷爷age

	Teacher17 tea;
	tea.father1age = 1; 
	tea.father2age = 2;
	tea.teaage = 3;
	tea.grandage = 4;

	cout << "断点在这里" << endl;

}

整理

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

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

相关文章

数据库管理-第141期 DG PDB - Oracle DB 23c(20240129)

数据库管理141期 2024-01-29 第141期 DG PDB - Oracle DB 23c&#xff08;20240129&#xff09;1 概念2 环境说明3 操作3.1 数据库配置3.2 配置tnsname3.3 配置强制日志3.4 DG配置3.5 DG配置建立联系3.6 启用所有DG配置3.7 启用DG PDB3.8 创建源PDB的DG配置3.9 拷贝pdbprod1文件…

TCP/IP网络模型

大家好我是苏麟 , 今天聊聊TCP/IP四层网络模型 . 资料来源 : 小林coding 小林官方网站 : 小林coding (xiaolincoding.com) 应用层 最上层的&#xff0c;也是我们能直接接触到的就是应用层&#xff08;Application Layer&#xff09;&#xff0c;我们电脑或手机使用的应用软件都…

测试ASP.NET Core项目调用EasyCaching的基本用法(InMemory)

EasyCaching属于开源缓存库&#xff0c;支持基本缓存方式及高级缓存用法&#xff0c;提高用户操作缓存的效率。EasyCaching支持的缓存方式包括以下类型&#xff0c;本文学习最基础的InMemory方式的基本用法。   EasyCaching.InMemory包属于基于内存的缓存库&#xff0c;使用的…

C语言——指针进阶(四)

目录 一.前言 二.指针和数组笔试题解析 2.1 二维数组 2.2 指针笔试题 三.全部代码 四.结语 一.前言 本文我们将迎来指针的结尾&#xff0c;包含了二维数组与指针的试题解析。码字不易&#xff0c;希望大家多多支持我呀&#xff01;&#xff08;三连&#xff0b;关注&…

JavaWeb后端登录校验功能(JWT令牌技术,Cookie技术,Session,拦截技术,过滤器)

目录 一.登录校验功能&#xff08;解决直接通过路径访问&#xff09; 1.实现思路 二.会话技术 ​编辑 1.Cookie技术 2.Session 3.令牌技术 1.简介 2.如何生成和解析 3.令牌的使用 三.Filter过滤器 1.什么是过滤器 2.实现步骤&#xff1a; 3.过滤器执行流程 4.拦截路径 5.过…

349. 两个数组的交集(力扣LeetCode)

文章目录 349. 两个数组的交集题目描述数组解题set容器解题该思路数组版解题 349. 两个数组的交集 题目描述 给定两个数组 nums1 和 nums2 &#xff0c;返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 示例 1&#xff1a; 输入&a…

【Linux】Linux下多线程

需要云服务器等云产品来学习Linux的同学可以移步/–>腾讯云<–/官网&#xff0c;轻量型云服务器低至112元/年&#xff0c;优惠多多。&#xff08;联系我有折扣哦&#xff09; 文章目录 1. 前置&#xff1a;进程地址空间和页表1.1 如何看待进程地址空间和页表1.2 虚拟地址…

练习12.6_横向射击_Python编程:从入门到实践(第3版)

编写一个游戏&#xff0c;将一艘飞船放在屏幕左侧&#xff0c;并允许玩家上下移动飞船。在玩家按空格键时&#xff0c; 让飞船发射一颗在屏幕中向右飞行的子弹&#xff0c;并在子弹从屏幕中消失后将其删除。 ship_shooting.py import pygame import sys from leftship impor…

​ArcGIS Pro 如何批量删除字段

在某些时候&#xff0c;我们得到的图层属性表内可能会有很多不需要的字段&#xff0c;如果挨个去删除会十分的麻烦&#xff0c;对于这种情况&#xff0c;我们可以使用工具箱内的字段删除工具批量删除&#xff0c;这里为大家介绍一下使用方法&#xff0c;希望能对你有所帮助。 …

[C++历练之路]C++中的继承小学问

W...Y的主页 &#x1f60a; 代码仓库分享&#x1f495; &#x1f354;前言&#xff1a; C中&#xff0c;继承是一种面向对象编程的重要概念&#xff0c;它允许一个类&#xff08;子类/派生类&#xff09;从另一个类&#xff08;父类/基类&#xff09;继承属性和方法。继承是…

C语言系列-整数在内存中的存储大小端字节序

&#x1f308;个人主页: 会编程的果子君 ​&#x1f4ab;个人格言:“成为自己未来的主人~” 目录 整数在内存中的存储 大小端字节序和字节序判断 什么是大小端 为什么会有大小端 练习 整数在内存中的存储 在讲解操作符的时候&#xff0c;我们就讲过了下面的内容 整数的2…

HashMap基本使用

特点&#xff1a; ①HashMap是Map里面的一个实现类。②没有额外需要学习的特有方法&#xff0c;直接使用Map里面的方法就可以了。③特点都是由键决定的&#xff1a;无序、不重复、无索引④HashMap跟HashSet底层原理是一模一样的&#xff0c;从名字可以看出来&#xff0c;都是哈…

MySQL原理(一)架构组成(2)逻辑模块组成

总的来说&#xff0c;MySQL可以看成是二层架构&#xff0c;第一层我们通常叫做SQL Layer&#xff0c;在MySQL数据库系统处理底层数据之前的所有工作都是在这一层完成的&#xff0c;包括权限判断&#xff0c;sql解析&#xff0c;执行计划优化&#xff0c;query cache的处理等等&…

麒麟系统—— openKylin 安装 Nacos

麒麟系统—— openKylin 安装 Nacos 一、准备工作1. 确保麒麟系统 openKylin 已经安装完毕。2. 确保 java 已经安装完毕3. 确保 Maven 已经安装完毕 二、下载 nacos三、解压与运行解压 关于 nacos 配置 本文将分享如何在麒麟系统 openKylin 上安装 Nacos。 一、准备工作 1. …

深度学习之卷积神经网络

卷积神经网络简称为CNN 首先我们来回顾一下&#xff0c;我们之前学到的全连接的神经网络&#xff1a; 上面我们通过线性层串行连接起来的神经网络&#xff0c;我们叫做全链接的网络&#xff0c;在线性层里面&#xff0c;我们的输入值和任意的输出值之间都存在权重&#xff0c;…

《HTML 简易速速上手小册》第10章:HTML 的维护与优化(2024 最新版)

文章目录 10.1 网页性能优化10.1.1 基础知识10.1.2 案例 1&#xff1a;优化网页图像10.1.3 案例 2&#xff1a;使用延迟加载优化性能10.1.4 案例 3&#xff1a;优化 CSS 和 JavaScript 的加载 10.2 SEO 最佳实践10.2.1 基础知识10.2.2 案例 1&#xff1a;创建一个 SEO 友好的博…

伊恩·斯图尔特《改变世界的17个方程》毕达哥拉斯定理笔记

它告诉我们什么&#xff1f; 直角三角形的三个边之间有什么关系。 为什么重要&#xff1f; 它提供了几何和代数之间的重要联系&#xff0c;使我们能够根据坐标计算距离。它也催生出了三角学。 它带来了什么&#xff1f; 测绘、导航&#xff0c;以及较近代出现的狭义和广义相对论…

深入了解Matplotlib中的子图创建方法

深入了解Matplotlib中的子图创建方法 一 add_axes( **kwargs):1.1 函数介绍1.2 示例一 创建第一张子图1.2 示例二 polar参数的运用1.3 示例三 创建多张子图 二 add_subplot(*args, **kwargs):2.1 函数介绍2.2 示例一 三 两种方法的区别3.1 参数形式3.2 布局灵活性3.3 适用场景3…

基于YOLOv8的摄像头吸烟行为检测系统(Python源码+Pyqt6界面+数据集)

&#x1f4a1;&#x1f4a1;&#x1f4a1;本文主要内容:详细介绍了摄像头下吸烟行为检测系统&#xff0c;在介绍算法原理的同时&#xff0c;给出Pytorch的源码、训练数据集以及PyQt6的UI界面。在界面中可以选择各种图片、视频进行检测识别&#xff0c;可进行置信度、Iou阈值设定…

【linux】磁盘空间不足-常用排查和处理命令

【linux】磁盘空间不足-常用排查和处理命令 1.通查一下 df -h #查看服务器磁盘空间情况 du -hs * 2>/dev/null #列出各目录所占空间大小 或 du -h -d 1 2>/dev/null #列出各目录所占空间大小 1.1情况一 df 磁盘空间和du 目录空间占用相等&#xff0c…