C++对象模型学习
更新记录
时间 | 更新记录 |
---|---|---
2020年4月6日| 初稿 |
背景
- 自从转入iOS,学习到iOS的方法调度,runTime的知识,了解了一下iOS的对象模型。
- 为了对iOS有更深入的了解,也对之前所学习的C++做一些补充,特此先学习一下C++的对象模型(说来也惭愧,windows开发一年半,没有看到C++对象模型相关的书或者网文)
三种对象模型
简单对象模型
- 所有的成员变量、成员函数都作为对象在内存中的一部分
- 简单、粗暴
- 缺点:占用内存大,以生成对象个数线性递增。
- 函数是所有对象共用,其实没有必要每个对象都记录,可以统一到某个地方。
表格驱动模型
- 区分数据成员和函数成员
- 对象只存放数据表指针和函数表指针,所以对象内存固定
- 针对于简单对象模型,表格驱动模型把数据成员列表作为每个对象独有的内存数据,而成员函数表则作为所有对象共享的内存数据,即可以解决简单对象模型“占用内存多”的问题
- 缺点
- 无法支持多态(确切地说,支持起来就比较复杂或者麻烦)
- 查找数据成员时,较第一种方案多了一次寻址。而且每个对象都多了一个表格指针,内存升高了。
- (要知道C++可是非常重视性能的,每次查找数据成员都要多一次寻址,而数据成员可能用的很多)
- 调用成员函数时,较第一种方案多了一次寻址。
- 同上,C++的成员函数也可能调用的很频繁
当前的C++对象模型
- 对象第一个字节(32位系统下)存储虚函数表指针(如继承树上有虚函数)
- 虚函数一律放入虚函数表中,通过表格进行查找
- 虚函数表的第一个slot存放
type_info
,用以支持RTTI
- 后续依次存放父类到子类的(非静态)数据成员变量
- 成员函数和全局函数类似,存放在代码区,不存储在对象相关内存中。
- 优点
- 查找数据,直接根据基地址+偏移量进行查找即可
- 支持多态较简单
- 成员函数调用快,直接根据符号寻址即可调用。相比表格驱动模型,不必多寻址一次。
方法调度
- 虚函数调用
- 这也是面试中的高频考点
- 通过实际的对象指针(即this指针),查找虚表,调用虚表中对应的函数。
- 编译时所作工作
- 将父类的虚函数和子类的虚函数进行逻辑判断,确定子类的虚函数表中存放的虚函数,是父类的虚函数实现,还是子类的虚函数实现
- 运行时所作工作
- 子类对象实际调用虚函数时,在运行时查找虚函数表,才知道调用的是哪个函数(是父类的,还是子类的)
- 普通成员函数调用
- 和全局函数调用类似
- 注意:成员函数名必定不会冲突。
- 因为普通成员函数的第一个参数是this指针,即使不同的类,普通成员函数名相同,函数参数也不同。
参考资料
- 图说C++对象模型:对象内存布局详解
- 《深度探索C++对象模型》