当前位置: 首页 > news >正文

C++对象模型(一)

c++ 对象模型:

1,non-static 成员变量存储于每一个类对象中。它是属于对象的

2,static 成员变量存储于所有类对象之外。它不属于对象,而是属于类的,即没有创建类对象,这个成员也是存在的。

3,static 和 non-static 成员函数存储于所有类对象之外,它们是属于类的,即没有创建类对象,这两类成员也是存在的。

可以看出一个类对象的大小,取决于这个类的 non-static 成员变量,类对象大小肯定是来自于类,所以类的大小取决于类的 non-static 成员变量。

虚函数:

1,每一个类产生出一堆指向虚函数的指针(如果有虚函数),放在表格之中,这个表格被称为 virtual table(vtbl)

2,每一个类对象被添加一个指针,指向相关的虚表。这个指针被称为 vptr

所以一个类对象大概的内存模型是这样的:

这是书上的一个例子。这样可以直观的看出,这个类有一个non-static 成员 float _x,一个 static 成员 int _point_count, 一个static 函数 int PointCount(),两个non-static 函数,其中一个是构造函数,一个是普通函数 float x() ,而虚表指针是隐形的,指向了一个虚函数表,表里都是虚函数的地址,即表里都是指针(就是函数指针,即函数入口)。那实际的 C++ 对象模型是怎样的呢?下面看一个简单的例子:

#include <stdio.h>
#include <stdlib.h>#pragma pack(4)
class CTest
{
public:CTest(): mValue(200){}virtual ~CTest(){}private:int mValue;
};
#pragma pack()int main()
{CTest test;printf("sizeof CTest is %llu\n", sizeof(test));return 0;
}

使用GDB查看一个这个类对象内存模型里到底有哪些东西:

打印出对象的内存地址,然后我们就可以看看内存里保存了哪些信息:

 为什么打印内存地址后 12 个字节呢?因为这个类的大小是 12 字节,上面用了 #pragma pack(4)设置了 4 字节对齐,如果不设置的话,可能默认就是 8 字节对齐了(因为机器是64位的,指针长度就是 8 字节)。这样看来,前 8 个字节是指向虚表的指针,后 4 个字节就是成员变量 mValue = c8(十进制为 200)。虚表指针指向的是虚表的首地址,所以我们也可以看看虚表里保存了哪些函数指针:

其实从源码能看到只有一个虚函数,所以虚表应该只有一个函数指针,正好前 8 个字节。

但实际看来有两个函数指针,但都是指向 CTest::~CTest() 函数,这里不是很理解,有同学知道的话告知一下。

#include <stdio.h>
#include <stdlib.h>#pragma pack(4)
class CTest
{
public:CTest(): mValue(200){}virtual ~CTest(){}virtual void print(){printf("mValue = %d\n", mValue);}
private:int mValue;
};
#pragma pack()int main()
{CTest test;printf("sizeof CTest is %llu\n", sizeof(test));return 0;
}

 例子中多加了一个虚函数,我们再来看一下内存情况:

0x004007e0 就是 CTest::print() 函数入口,既然是函数,我们就可以直接调用了,如:

到这里唯一不理解的是有 2 个函数指针指向了 CTest::~CTest(),有同学知道告知一下。

相关文章:

  • Linux平台下安全编译
  • Git搭建
  • 通过FileZilla配置FTP
  • gitlab.rb主要配置
  • linux install nvm
  • 如何令containerd连接私有harbor
  • SQL基础知识(四)
  • Golang内置类型和函数及接口、Init函数和main函数
  • 无状态应用管理Deployment
  • 面试经典题---3.无重复字符的最长子串
  • php二次开发股票系统代码:腾讯股票数据接口地址、批量获取股票信息、转换为腾讯接口指定的股票格式
  • 幻兽帕鲁服务器数据备份
  • x-cmd pkg | httpx - 为 Python 设计的下一代 HTTP 客户端库
  • 04 SB实战 -微头条之头条模块(登录验证拦截器+发布文章+修改文章)
  • 分享7种SQL的进阶用法
  • 《Java编程思想》读书笔记-对象导论
  • 《微软的软件测试之道》成书始末、出版宣告、补充致谢名单及相关信息
  • 【162天】黑马程序员27天视频学习笔记【Day02-上】
  • 0基础学习移动端适配
  •  D - 粉碎叛乱F - 其他起义
  • el-input获取焦点 input输入框为空时高亮 el-input值非法时
  • ESLint简单操作
  • export和import的用法总结
  • IE报vuex requires a Promise polyfill in this browser问题解决
  • interface和setter,getter
  • Linux下的乱码问题
  • SpriteKit 技巧之添加背景图片
  • 分享一份非常强势的Android面试题
  • 记一次和乔布斯合作最难忘的经历
  • 如何使用 JavaScript 解析 URL
  • 完善智慧办公建设,小熊U租获京东数千万元A+轮融资 ...
  • #1014 : Trie树
  • #pragam once 和 #ifndef 预编译头
  • (10)Linux冯诺依曼结构操作系统的再次理解
  • (16)Reactor的测试——响应式Spring的道法术器
  • (附源码)springboot车辆管理系统 毕业设计 031034
  • (剑指Offer)面试题34:丑数
  • (经验分享)作为一名普通本科计算机专业学生,我大学四年到底走了多少弯路
  • (六)软件测试分工
  • (顺序)容器的好伴侣 --- 容器适配器
  • (算法二)滑动窗口
  • (图)IntelliTrace Tools 跟踪云端程序
  • .net core 6 集成和使用 mongodb
  • .NET Core引入性能分析引导优化
  • .NET 使用 XPath 来读写 XML 文件
  • .NET文档生成工具ADB使用图文教程
  • .ui文件相关
  • @Conditional注解详解
  • [AAuto]给百宝箱增加娱乐功能
  • [bug总结]: Feign调用GET请求找不到请求体实体类
  • [bzoj1038][ZJOI2008]瞭望塔
  • [fsevents@^2.1.2] optional install error: Package require os(darwin) not compatible with your platfo
  • [FUNC]判断窗口在哪一个屏幕上
  • [IE技巧] 如何让IE 启动的时候不加载任何插件
  • [jQuery]10 Things I Learned from the jQuery Source