C++对象在内存中的布局
1,C++ 对象模型:C++ 的对象在内存当中是如何排布的;
1,C++ 对象包含了成员变量和成员函数;
2,本文分析 C++ 对象它的成员变量在内存中如何排布的,C++ 对象它的成员函数在内存中是如何排布的;
2,回归本质:
1,class 是一种特殊的 struct:
1,class 用来定义类对象,类是一种特殊的结构体,class 这种特殊的结构体特殊在其访问权限默认为 private,struct 这种结构体定义成员的默认访问权限是 public,两者在 C++ 中的区别仅此而已,因此类是一种特殊的结构体这是一种本质;
2,在内存中 class 也就可以看做变量的集合;
3,class 与 struct 遵循相同的内存对齐规则;
1,计算结构体的大小同样也适用于计算类的大小;
4,class 中的成员函数与成员变量是分开存放的;
1,每个对象有独立的成员变量;
1,成员变量是数据,数据只可能存放在栈空间(运行时)、堆空间(运行时)、全局数据区这三个区域;
2,所有对象共享类中的成员函数;
1,成员函数是函数,只可能存放在代码段里;
2,值得思考的问题:
1 class A struct B 2 { { 3 int i; int i; 4 int j; int j; 5 char c; char c; 6 double d; double d; 7 }; }; 8 9 sizeof(A) = ? sizeof(B) = ?
3,对象内存布局初探编程实验:
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class A 7 { 8 int i; 9 int j; 10 char c; 11 double d; 12 public: 13 void print() // 虽然写在一起,但是在内存中的排布是在不同的地方的; 14 { 15 cout << "i = " << i << ", " 16 << "j = " << j << ", " 17 << "c = " << c << ", " 18 << "d = " << d << endl; 19 } 20 }; 21 22 struct B 23 { 24 int i; 25 int j; 26 char c; // 虽然 char 类型大小为 1 个字节,但是由于内存对齐,其大小为 4 个字节,其中三个字节是内存空隙; 27 double d; 28 }; 29 30 int main() 31 { 32 A a; 33 34 cout << "sizeof(A) = " << sizeof(A) << endl; // 20 bytes,数据类型本质就是固定内存空间大小的别名; 35 cout << "sizeof(a) = " << sizeof(a) << endl; // 20 bytes,C++ 对象中并没有包含成员函数,其仅仅代表成员变量的集合; 36 cout << "sizeof(B) = " << sizeof(B) << endl; // 20 bytes 37 38 a.print(); // 打印乱码 39 40 B* p = reinterpret_cast<B*>(&a); // 用 reinterpret_cast 重解释 a 对象所代表的这一段内存; 41 42 /* 将 a 对象当做一个结构体 B 的变量来使用;由于 a 里面的成员变量在内存空间里面的排布与 struct B 在内存空间里面的排布是一样的,所有就可以通过下列方式就可以修改 a 对象里面的私有成员 */ 43 p->i = 1; 44 p->j = 2; 45 p->c = 'c'; 46 p->d = 3; 47 48 a.print(); // 打印 i = 1, j = 2, c = c, d = 3;这里结果说明一个对象真的就是一个结构体;可以将一个对象当做一个结构体来使用; 49 50 p->i = 100; 51 p->j = 200; 52 p->c = 'C'; 53 p->d = 3.14; 54 55 a.print(); // 打印 i = 100, j = 200, c = C, d = 3.14,不是巧合 56 57 return 0; 58 }
4,C++ 对象模型分析:
1,运行时的对象退化为结构体的形式:
1,所有成员变量在内存中依次排布;
1,像结构体中的一样依次排布;
2,所有变量间可能存在内存空隙;
1,内存对齐;
3,可以通过内存地址直接访问成员变量;
1,地址赋值给指针;
4,访问权限关键字在运行时失效;
1,private 和 protected 的访问权限仅在编译时候有效;
2,成员函数运行方式:
1,类中成员函数位于代码段中;
2,调动成员函数时对象地址作为参数隐式传递;
1,对象通过点操作符调用成员函数,点操作符的背后,编译器将对象的地址传递到了成员函数的内部;
2,成员函数为何能够访问(无权限)成员变量,在内存中是分开存放的,有什么理由成员函数内部就可以直接访问到对象的成员变量 呢?
3,就是由于这个隐藏了的地址传递过程,C++ 编译器在编译成员函数调用的时候,隐藏的传递了对象的地址,在成员函数的内部有了这个隐藏的地址当然可以直接访问对象的成员变量,这就很好的解释了 this指针,这个指针只能在成员函数内部使用,其代表当前对象,并保存了对象的地址;
3,成员函数通过对象地址访问成员变量;
4,C++ 语法规则隐藏了对象地址的传递过程;
5,对象本质分析编程实验:
1,C++ 程序;
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class Demo 7 { 8 int mi; 9 int mj; 10 public: 11 Demo(int i, int j) 12 { 13 mi = i; 14 mj = j; 15 } 16 17 int getI() 18 { 19 return mi; 20 } 21 22 int getJ() 23 { 24 return mj; 25 } 26 27 int add(int value) 28 { 29 return mi + mj + value; 30 } 31 }; 32 33 int main() 34 { 35 Demo d(1, 2); 36 37 cout << "sizeof(d) = " << sizeof(d) << endl; // 8 bites; 38 cout << "d.getI() = " << d.getI() << endl; // 1; 39 cout << "d.getJ() = " << d.getJ() << endl; // 2; 40 cout << "d.add(3) = " << d.add(3) << endl; // 6; 41 42 return 0; 43 }
2,用 C 语言完成上述面向对象程序:
1,50-2.h 头文件:
1 #ifndef _50_2_H_ 2 #define _50_2_H_ 3 4 typedef void Demo; // 定义一个新的类型(作为类类型,这里能看到的也只有这个类型); 5 6 Demo* Demo_Create(int i, int j); // 作为构造函数看待;C++ 中之所以没有返回值,是因为已经存在了; 7 int Demo_GetI(Demo* pThis); // 地址的传递过程,用 pThis 实现; 8 int Demo_GetJ(Demo* pThis); 9 int Demo_Add(Demo* pThis, int value); 10 void Demo_Free(Demo* pThis); // C 中编译器不可能提供析构函数,要自己定义;C++ 中之所以没有返回值,是因为已经存在了; 11 12 #endif
2,50-2.c 实现文件:
1 #include "50-2.h" 2 #include "malloc.h" 3 4 /* 结构体代表真正的类,反映了 class 这个类的本质就是结构体 */ 5 struct ClassDemo 6 { 7 int mi; 8 int mj; 9 }; 10 11 /* 实现构造函数 */ 12 /* 其实我们实实在在的定义了这个结构体,但是对于用户而言,根本没有必要知道这个类是如何实现的,对于一个类的用户而言,只用知道如何使用成员函数就可以了 */ 13 Demo* Demo_Create(int i, int j) // 构造函数没有 this 指针; 14 { 15 struct ClassDemo* ret = (struct ClassDemo*)malloc(sizeof(struct ClassDemo)); // C 中需要加 struct; 16 17 if( ret != NULL ) 18 { 19 ret->mi = i; 20 ret->mj = j; 21 } 22 23 return ret; 24 } 25 26 int Demo_GetI(Demo* pThis) // pThis 代表当前对象 27 { 28 struct ClassDemo* obj = (struct ClassDemo*)pThis; 29 30 return obj->mi; 31 } 32 33 int Demo_GetJ(Demo* pThis) 34 { 35 struct ClassDemo* obj = (struct ClassDemo*)pThis; 36 37 return obj->mj; 38 } 39 40 int Demo_Add(Demo* pThis, int value) 41 { 42 struct ClassDemo* obj = (struct ClassDemo*)pThis; 43 44 return obj->mi + obj->mj + value; 45 } 46 47 void Demo_Free(Demo* pThis) 48 { 49 free(pThis); 50 }
3,使用文件:
1 #include <stdio.h> 2 #include "50-2.h" 3 4 int main() 5 { 6 Demo* d = Demo_Create(1, 2); // d 代表一个指针,指向一个对象;等价的 C++ 中的代码为 Demo* d = new Demo(1, 2); 7 8 printf("d.mi = %d\n", Demo_GetI(d)); // d->getI(); 9 printf("d.mj = %d\n", Demo_GetJ(d)); // d->getJ(); 10 printf("Add(3) = %d\n", Demo_Add(d, 3)); // d->add(3); 11 12 // d->mi = 100; // 1,warning: dereferencing 'void *' pointer (正在间接引用空指针);error: request for member 'mi' in something not a structure or union (在非结构体和联合体中访问成员 mi) ; 13 // 2,面向对象的观点来看,mi 是私有的,类的外部不可以访问,只能通过成员函数访问,这是面向对象中的信息隐藏; 14 // 3,在 C 语言中,没有 private 关键字,因此我们只能用 typedef void Demo 这样的技术,通过定义一个 void 的 Demo 来进行信息隐藏,进行 private 的模拟; 15 16 Demo_Free(d); 17 18 return 0; 19 }
1,这个程序告诉我们,面向对象它不是 C++ 专属,我们依然可以用 C 语言写面向对象;
2,更深层的就是,C++ 编译器在背后做了很多的事情,我们有必要了解这个事情是如何发生的;
3,对于一个类而言,成员变量和成员函数是分开存放的,这一点是非常重要, 如果掌握了这个本质,我们用任何语言,都可以写出面向对象的代码;
6,小结:
1,C++ 中的类对象在内存布局上与结构体相同;
1,本质就是:class 是一种特殊的 struct;
2,成员变量和成员函数在内存中分开存放;
3,访问权限关键字在运行时失效;
4,调用成员函数时对象地址作为参数隐式传递;
转载于:https://www.cnblogs.com/dishengAndziyu/p/10915336.html
C++对象在内存中的布局相关推荐
- JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配
文章目录 前言 零.排序规范 1.happens-before原则 2.找文档位置 一.一线互联网企业关于对象面试题: (后面回答的就是这几个问题) 二.对象创建过程 三.对象在内存中的存储布局 1. ...
- C++类对象在内存中的布局
目录 一.前言 二.C++ 类对象的内存布局 2.1 只有数据成员的对象 2.2 没有虚函数的对象 2.3 拥有仅一个虚函数的类对象 2.4 拥有多个虚函数的类对象 三.继承关系中的C++类对象内存分 ...
- java对象在内存中的布局
目录 如何查看对象的大小 分析java对象的组成 普通对象 数组对象 如何查看对象的大小 这里介绍一种工具JOL:Java Object Layout( java对象布局) 这个工具可以查看对象大小 ...
- python里面的类和对象_Python中类和对象在内存中是如何保存?
类以及类中的方法在内存中只有一份,而根据类创建的每一个对象都在内存中需要存一份,大致如下图: 如上图所示,根据类创建对象时,对象中除了封装 name 和 age 的值之外,还会保存一个类对象指针,该值 ...
- java对象的内存结构_Java对象在内存中的结构分析
问题:在Hotspot JVM中,32位机器下,Integer对象的大小是int的几倍? HotSpot虚拟机中,对象在内存中的布局分为三块区域:对象头.实例数据和对齐填充,其中对象头又分为:Mark ...
- 对象在内存中的存储布局
对象头包含: markword(和锁相关的信息) 8字节 class pointer(说明对象属于哪个类),jvm指针八字节,但是默认压缩,所有4个字节 对象体包含: instance word实例 ...
- [转载] java对象在内存中的结构
参考链接: 了解Java中的类和对象 今天看到一个不错的PPT:Build Memory-efficient Java Applications,开篇便提出了一个问题,在Hotspot JVM中,32 ...
- 实现 对象在内存中的引用一致性 之第一步
原委 废话不要,他们都该删. 虽然写了个 基于数据库的代码生成器 与大家分享,但并不擅长数据库开发:相反,面向对象才是我的爱. 多年的酝酿让我收获良多,直觉这是个令人激动的开发模式. 或许是因为高中学 ...
- 单个对象和多个对象在内存中的结构图
单个对象在内存中的结构图: 多个对象在内存中的结构图: (注:图片来至http://www.itheima.com/ 视频教程截图,转载请说明出处)
最新文章
- char[],char *,string之间转换
- 基础理论:集合的Hausdorff距离
- java main是多线程的吗_Java多线程之线程及其常用方法
- boost::undirected_dfs用法的测试程序
- 【渝粤题库】陕西师范大学200371 拓扑学 作业 (专升本、高起本)
- log4j+mybatis打印日志文件
- ActionScript 3 step by step (2) - 使用Trace()跟踪输出
- 通俗的说这是一个一对多的例子,看看人家是怎么做的!
- 苹果计算机怎么添加在快捷方式,如何在 iPhone 主屏幕上添加文件快捷方式?
- WordPress 后台评论如何自定义搜索条件
- DiskFileUpload 中文乱码 解决方法
- 个税计算器-springboot开发实现
- vue 批量下载通用方法
- 万字详解 Docker 镜像详细操作
- java 如何理解new_JAVA中new的 理解
- 登录注册小程序(JAVA基础案例教程第二章-课后作业)
- linux脚本执行SQL文件创建表,shell脚本执行sql文件chrome安装
- 向量组a可由向量组b线性表示什么意思
- resetFields方法重置表单
- 吃饭理论,抓沙理论,杯子理论——结构化学习,实现N+1,时间管理
热门文章
- 云丁智能锁使用说明书_出门不再带钥匙 云丁D2F智能指纹锁新体验
- 服务器共享文件监控,服务器共享文件监控
- activity finish后没有destroy_Activity 基础知识点
- sysoper在oracle是什么意思,oracle用户 sysdba 与system,sysoper的区别
- mysql临时表如何分页_sql server 与 mysql 分页查询以及创建临时表的区别
- linux c 获取 多个硬盘序列号_veket系统中使用GParted进行硬盘分区
- php加密密码解析,php密码加密解密
- java 非模态_统计图钻取的明细报表在非模态窗口中显示
- linux服务器 授权命令,linux的Sudo/su授权命令详解
- java try catch_Java - 异常处理机制