84 C++对象模型探索。数据语义学 - 继承多个类的时的数据布局问题。

news2024/11/14 1:11:44

此章节分析多继承问题,难点,但是非重点,实际开发中,多继承用的很少,容易被code review,可以不看。

我们要访问一个类对象中的成员
成员的定位是通过如下两个因素决定的:this指针(编译器会自动调整) ,以及该成员的偏移量,
这样this指针的调整,都需要编译器的介入来完成。

Teacher  继承 Teacher1,继承Teacher2,继承Teacher3

//多继承下的成员布局分析

class Teacher13base1 {
public:
	Teacher13base1() {
		cout << "Teacher13base1 gouzao this = " << this << endl;
	}
public:
	int base1age;

private:
	int base1privateage;
public:
	virtual void base1virtualfunc() {

	}
};

class Teacher13base2 {
public:
	Teacher13base2() {
		cout << "Teacher13base2 gouzao this = " << this << endl;
	}
public:
	int base2age;

private:
	int base2privateage;
public:
	virtual void base2virtualfunc() {

	}
};

class Teacher13base3 {
public:
	Teacher13base3() {
		cout << "Teacher13base3 gouzao this = " << this << endl;
	}
public:
	int base3age;

private:
	int base3privateage;
public:
	virtual void base3virtualfunc() {

	}
};

class Teacher13 :public Teacher13base1, public Teacher13base2, public Teacher13base3{
public:
	Teacher13() {
		cout << "Teacher13 gouzao this = " << this << endl;
	}
public:
	int age;

private:
	int privateage;
public:
	virtual void virtualfunc() {

	}
};

void main() {

	cout << sizeof(Teacher13base1) << endl;//12  Teacher13base1的vptr + 2ge int
	cout << sizeof(Teacher13base2) << endl;//12  Teacher13base2的vptr + 2ge int
	cout << sizeof(Teacher13base3) << endl;//12  Teacher13base3的vptr + 2ge int
	cout << sizeof(Teacher13) << endl;//44    8个 int = 32 + 3个vptr(Teacher13base1的vptr(Teacher13的vptr	) + Teacher13base2的vptr + Teacher13base3的vptr )

	printf("Teacher13::base1age的地址是%p\n", &Teacher13::base1age);
	printf("Teacher13::base2age的地址是%p\n", &Teacher13::base2age);
	printf("Teacher13::base3age的地址是%p\n", &Teacher13::base3age);
	printf("Teacher13::base1age的地址是%p\n", &Teacher13::age);
	Teacher13 tea;
	tea.base1age = 1;
	tea.base2age = 2;
	tea.base3age = 3;
	tea.age = 4;

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

}


12
12
12
44
Teacher13::base1age的地址是00000004
Teacher13::base2age的地址是00000004
Teacher13::base3age的地址是00000004
Teacher13::base1age的地址是00000024
Teacher13base1 gouzao this = 012FFB10
Teacher13base2 gouzao this = 012FFB1C
Teacher13base3 gouzao this = 012FFB28
Teacher13 gouzao this = 012FFB10
断点在这里

分析

0x012FFB10  f4 3e 9c 00 01 00 00 00 cc cc cc cc 04 3f 9c 00 02 00 00 00 cc cc cc cc 10 3f 9c 00  
0x012FFB2C  03 00 00 00 cc cc cc cc 04 00 00 00 cc cc cc cc

f4 3e 9c 00  Teacher13base1 的vptr指针的地址,也是Teacher13的vptr指针的地址

01 00 00 00  Teacher13base1.base1age

cc cc cc cc  Teacher13base1.base1privateage
 
04 3f 9c 00  Teacher13base2 的vptr指针的地址
 
02 00 00 00  Teacher13base2.base2age
 
cc cc cc cc  Teacher13base2.base2privateage
  
10 3f 9c 00  Teacher13base3 的vptr指针的地址
  
03 00 00 00  Teacher13base3.base3age
  
cc cc cc cc  Teacher13base3.base3privateage

04 00 00 00  teacher13.age

cc cc cc cc  teacher13.privateage

继承多个类的时候,最终子类和第一个继承的父类公用 vptr,this指针指向相同

其他父类的this指针都和tea不一样

其他父类的vptr都在原来的位置上。

那么根据上述的结论,如下的代码会怎么样呢?


	Teacher13 tea13;

	cout << "tea13的地址为:" << &tea13 << endl;

	Teacher13base2 *pbase2 = &tea13;
	cout << "pbase2的地址为:" << pbase2 << endl;

tea13的地址为:006BFB3C
pbase2的地址为:006BFB48

这个结论我们已经知道了,Teacher13base2 的 this指针会想下移动12字节,因此这两值不一样。

从编译器的角度分析,那么一定是在Teacher13base2 *pbase2 = &tea13这一行做了额外的事情。

//Teacher13base2 *pbase2 = (Teacher13base2*)(  ((char*)&tea13) + sizeof(Teacher13base1));

放开这一行测试结果如下:

tea13的地址为:00CFF82C
pbase2的地址为:00CFF838

总结上面的例子:

	Teacher13 tea13;

	cout << "tea13的地址为:" << &tea13 << endl;

	Teacher13base2 *pbase2 = &tea13;
	cout << "pbase2的地址为:" << pbase2 << endl;
	//站在编译器角度,是这么干的
	Teacher13base2 *pbase3 = (Teacher13base2*)(((char*)&tea13) + sizeof(Teacher13base1));
	cout << "pbase2的地址为:" << pbase3 << endl;
}

tea13的地址为:012FFA10
pbase2的地址为:012FFA1C
pbase2的地址为:012FFA1C

    //再来看一个特殊的

	//再来看一个特殊的

	Teacher13base2 *pbase4 = new Teacher13();//这句话的理解是:new Teacher13肯定是创建了44个字节的数据。但是this指针是Teacher13base2* 的,因此this指针是指向 内存模型的中间的位置
	//delete pbase4;//那么这样delete,相当于在内存模型的中间位置delete,会有runtime exception

	//那么要怎么删除呢?再转化成 teacher13 *,然后再delete

	Teacher13 * temppbase4 = (Teacher13 *)pbase4;
	delete temppbase4;

	//实际上编译器内部是这么干的
	//Teacher13 * temppbase5 = (Teacher13 *)((char *)pbase4 -sizeof(Teacher13base1));
	//delete temppbase5;

上述一些特殊的case,都是因为多继承引起的,多继承的时候,使用了非第一个继承的指针,指向子类对象,由于new 出来的是整个子类对象,但是this指针因为调整的问题,确不在最 子类对象的最上面。

建议少用多继承。

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

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

相关文章

数字身份保护:Web3如何改变个人隐私观念​

随着Web3时代的来临&#xff0c;数字身份保护成为人们关注的焦点之一。Web3技术的引入不仅为个人隐私带来了新的挑战&#xff0c;同时也为我们重新思考和改变个人隐私观念提供了契机。本文将深入探讨Web3如何改变个人隐私观念&#xff0c;以及在数字身份保护方面的创新举措。 1…

springboot中获取配置文件中属性值的几种方式

目录 第一章、使用Value注解第二章、使用PropertySource注解第三章、使用Configurationproperties注解第四章、使用Java Properties类第五章、使用Environment接口 友情提醒: 先看文章目录&#xff0c;大致了解文章知识点结构&#xff0c;点击文章目录可直接跳转到文章指定位置…

财务数据可视化大屏:企业决策的智慧之眼

在大数据时代&#xff0c;财务数据的管理与分析对于企业的决策和发展至关重要。然而&#xff0c;面对海量的数据&#xff0c;如何快速、准确地获取有价值的信息&#xff0c;一直是企业面临的挑战。这时&#xff0c;财务数据可视化大屏的出现&#xff0c;为企业提供了一个全新的…

VS2019卸载VA插件之后,出现闪退时

https://learn.microsoft.com/zh-cn/visualstudio/ide/reference/safemode-devenv-exe?viewvs-2022 采用安全模式进入VS。 以管理员运行VS2019命令行窗口&#xff1a; 进入VS界面后&#xff0c;再关掉&#xff0c;重新按正常方式打开VS界面即可

webassembly003 TTS BARK.CPP-02-bark_tokenize_input(ctx, text);

bark_tokenize_input函数 bark是没有语言控制选项的&#xff0c;但是官方的版本无法运行中文bark_tokenize_input会调用bert_tokenize函数&#xff0c;bark_tokenize_input函数对中文分词失效&#xff0c;也就是导致不支持中文的原因。 void bark_tokenize_input(struct bark_…

File、IO流(一)

File、IO流 File File是Java.io包下的类&#xff0c;File类的对象&#xff0c;用于代表当前操作系统的文件&#xff08;可以是文件、或者文件夹&#xff09;。 注意&#xff1a;File类只能对文件本身进行操作&#xff0c;不能读写文件里面存储的数据。 IO流 用于读写数据的&…

Unity3d实现简单的战斗

使用u3d实现一个简单的战斗demo&#xff0c;记下学到的知识点&#xff0c;以备后查。 1.判断是否点中指定物体 if (Input.GetMouseButton(0)) {Ray ray Camera.main.ScreenPointToRay(Input.mousePosition);if (Physics.Raycast(ray, out RaycastHit hit)){//坐标转换Vector…

数据结构—栈实现后缀表达式的计算

后缀表达式计算 过程分析 中缀表达式 &#xff08;15&#xff09;*3 > 后缀表达式 153* (可参考这篇文章&#xff1a;中缀转后缀) 第一步&#xff1a;我们从左至右扫描 后缀表达式(已经存放在一个字符数组中)&#xff0c;遇到第一个数字字符 ‘1’ 放入栈中第二步&#xf…

springboot本地测试

文章目录 本地测试引入依赖进入StudentMapper右键点击生成 项目结构 本地测试 引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope> </d…

[Tcpdump] 网络抓包工具使用教程

往期回顾 海思 tcpdump 移植开发详解海思 tcpdump 移植开发详解 前言 上一节&#xff0c;我们已经讲解了在海思平台如何基于静态库生成 tcpdump 工具&#xff0c;本节将作为上一节的拓展内容。 一、tcpdump 简介 「 tcpdump 」是一款强大的网络抓包工具&#xff0c;它基于…

Redis学习——高级篇⑥

Redis学习——高级篇⑥ Redis7高级之简单实现布隆过滤器BloomFilter &#xff08;七&#xff09; 7 布隆过滤器1. 是什么2.能干嘛3.实现原理和数据结构4.使用三步骤5.尝试手写简单的布隆过滤器&#xff0c;结合bitmap1.整体架构2.步骤设计3 springboot redis mybatis布…

微信扫码登录流程

微信官方文档使用 搜索“微信开放平台”点击导航栏的“资源中心”点击“网站应用”下的“微信登录功能”地址微信扫码登录是基于OAuth2的&#xff0c;所以需要第三方应用&#xff08;就是实现微信扫码登录的应用&#xff09;成为微信的客户端&#xff0c;获取AppId和AppSecret…

PMP备考笔记:模拟考试知识点总结

1. 答题思路&#xff1a;优先看问题&#xff0c;可节省时间。 2. 考试就按照考试的套路来做&#xff0c;不要过多考虑。 开发团队只专注当前冲刺目标&#xff0c;产品负责人对PB排优先级。 收集需求工具-原型法&#xff1a;能够让用户提前体验&#xff0c;减少返工的风险。 …

基于ldap实现登录认证

最近开发的应用需要外协人员实现登录认证&#xff0c;外协人员的密码等信息已经录入到ldap, 需要连接ldap进行登录认证。下面先介绍一下登录的网络旅程图。 一.nginx实现AES加密 nginx请求处理入口&#xff08;前端请求为json格式&#xff09; location /aes {default_type te…

解锁Web3:数字未来的大门

随着科技的不断推进&#xff0c;我们正站在数字时代的新门槛上。Web3&#xff0c;作为互联网的下一个演进阶段&#xff0c;正在逐渐揭开数字未来的面纱。本文将深入探讨Web3的本质、对社会的影响以及在数字时代中所扮演的关键角色。 什么是Web3&#xff1f; Web3是互联网发展的…

数据分析讲课笔记02:科学计算库Numpy

文章目录 零、学习目标一、认识NumPy数组对象&#xff08;一&#xff09;N维数组对象ndarray&#xff08;二&#xff09;ndarray对象重要的属性&#xff08;三&#xff09;ndarray数组案例演示 二、创建NumPy数组&#xff08;一&#xff09;采用array()函数创建数组&#xff08…

父元素flex:1 高度却被子元素撑开的问题

问题 当父元素设置了flex: 1; 的情况下&#xff0c;想在其中子元素超出父元素高度的情况下&#xff0c;产生滚动条&#xff0c;在父元素区域滚动。由于子元素高度不固定&#xff0c;故父元素设置为display: flex; flex-direction: column; 子元素设置flex: 1; overflow: auto;…

select的change方法如何传递多个参数

element-ui中select的change方法传递多个参数 element-ui中的select&#xff0c;checkbox等组件的change方法的回调函数只有当前选择的val&#xff0c;如果想再传入自定义参数怎么办&#xff1f; 不能够传入自定义的参数&#xff0c;在进行某些操作时&#xff0c;会比较困难&…

【Java程序设计】【C00179】基于SSM的电影在线购票管理系统(论文+PPT)

基于SSM的电影在线购票管理系统&#xff08;论文PPT&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于ssm的电影在线购票管理系统 本系统分为前台用户和后台管理员2个功能模块。 前台用户&#xff1a;当游客打开系统的网址后&#xff0c;首先看到…

【开源】基于JAVA+Vue+SpringBoot的用户画像活动推荐系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 兴趣标签模块2.3 活动档案模块2.4 活动报名模块2.5 活动留言模块 三、系统设计3.1 用例设计3.2 业务流程设计3.3 数据流程设计3.4 E-R图设计 四、系统展示五、核心代码5.1 查询兴趣标签5.2 查询活动推荐…