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

C++对象模型

C++对象模型是C++语言中关于对象如何在内存中布局和如何工作的底层机制。理解C++对象模型对于编写高效、正确的C++代码非常重要。

基本概念

  1. 对象内存布局:C++对象在内存中的组织方式

  2. 虚函数机制:实现运行时多态的基础

  3. 继承模型:单继承、多继承和虚继承的实现

  4. 成员访问:成员变量和成员函数的访问机制

不含有有虚函数的对象模型

对于不包含虚函数的简单类:

内存布局:

  • 成员变量按声明顺序排列

  • 成员函数不占用对象空间(存储在代码区)

 空类的大小:

  • 如果一个类没有任何数据成员(包括静态成员),它的大小通常是 1字节(具体取决于编译器和内存对齐规则)。

带有虚函数的对象模型

当类包含虚函数时,编译器会添加一个虚函数表指针(vptr):

内存布局:

  1. 虚表指针(vptr)指向虚函数表(vtable)

  2. 然后是成员变量

  3. 虚函数表中存储着虚函数地址

 

继承模型

单继承

 1、对一般继承而言,若子类重写(overwrite)了父类的虚函数,则子类虚函数将覆盖虚表中对应的父类虚函数(注意子类与父类拥有各自的一个虚函数表);

2、若子类并无overwrite父类虚函数,而是声明了自己新的虚函数,则该虚函数地址将扩充到虚函数表最后。

3、而对于虚继承,若子类overwrite父类虚函数,同样地将覆盖父类子物体中的虚函数表对应位置,而若子类声明了自己新的虚函数,则编译器将为子类增加一个新的虚表指针vptr,这与一般继承不同。

多继承 

1、一般多继承 (非菱形继承)

        如果继承于多个基类,且这个多个基类中有虚函数,那么 这个类 会有多个虚函数表。

这个类的对象会有多个虚函数表指针。

         子类的虚函数被放在声明的第一个基类的虚函数表中。

        overwrite时,所有基类的同名虚函数都被子类的同名虚函数覆盖。这样做就是为了解决不同的基类类型的指针指向同一个子类实例,而能够调用到实际的函数。

        内存布局中,父类按照其声明顺序排列。

2、菱形继承
class A { int data; };
class B : public A { int b_data; };
class C :public A { int c_data; };
class D :public B, public c { int d_data; };

 

 问题:D的对象会包含两份 A 的成员。通过D 访问A 的成员 data 会编译错误,需要通过 B::data 或 C::data 明确路径。

内存布局

 

         相较于一般多继承,公共继承类在两个虚表中都有。

3.虚继承
class A { int data; };
class B : virtual public A { int b_data; };
class C : virtual  public A { int c_data; };
class D : public B, public c { int d_data; };

 最终派生类负责构造虚基类
注意:在虚继承的情况下,虚基类的构造由最底层的派生类直接负责,而不是由中间的基类来
构造过程:
1、先造虚基类A
由 D的构造函数直接调用 A的构造函数(B和C的造函数不再调用 A)
2、按照声明顺序构造:先 B,后 C
3、D的自身构造

         解决菱形继承的问题。

this指针调整

在多继承中,当派生类指针转换为基类指针时,可能需要调整this指针的值:

Derived* d = new Derived;
Base2* b2 = d;  // 可能需要调整指针值

对象构造与析构过程

  1. 分配内存

  2. 构造基类子对象

  3. 构造成员对象

  4. 执行构造函数体

  5. 析构顺序相反

运行时类型识别(RTTI)

通过type_info对象实现,通常与虚函数表存储在一起。

性能考虑

  1. 虚函数调用比普通函数调用多一次间接寻址

  2. 多重继承可能增加空间开销

  3. 虚继承会增加访问虚基类成员的开销

理解C++对象模型有助于编写更高效的代码,并更好地理解C++的底层机制。

http://www.dtcms.com/a/298980.html

相关文章:

  • CH341 Linux驱动 没有 /dev/ttyCH341USB0
  • 前端模块化开发实战指南
  • kafka中生产者的数据分发策略
  • starrocks官网docker部署mysql无法连接
  • 影刀RPA_Temu关键词取数_源码解读
  • RK3568笔记九十三:基于RKNN Lite的YOLOv5目标检测
  • 高性能网络DPDK、RDMA、XDP初探
  • VTK交互——ClientData
  • Java程序员学从0学AI(六)
  • Baumer工业相机堡盟工业相机如何通过YoloV8深度学习模型实现轮船检测识别(C#代码UI界面版)
  • 热传导问题Matlab有限元编程 :工业级热仿真核心技术-搭建热传导求解器【含案例源码】
  • CSS3知识补充
  • 【企业架构】TOGAF概念之二
  • 基于深度学习的图像分类:使用Capsule Networks实现高效分类
  • 【Linux手册】操作系统如何管理存储在外设上的文件
  • 用 FFmpeg 把视频输出为图片序列
  • 创建 Vue 项目的 4 种主流方式
  • 小程序的客服咨询(与企业微信建立沟通)
  • [论文阅读] 人工智能 + 软件工程 | NoCode-bench:评估LLM无代码功能添加能力的新基准
  • 使用Python实现单词记忆软件
  • Day 22: 复习
  • Datawhale AI 夏令营—科大讯飞AI大赛(大模型技术)—让大模型理解表格数据(列车信息表)
  • 【影刀RPA_初级课程_我的第一个机器人】
  • .bat 打开方式恢复
  • 秋招Day20 - 微服务 - 概念
  • 大模型应用班-第2课 DeepSeek使用与提示词工程课程重点 学习ollama 安装 用deepseek-r1:1.5b 分析PDF 内容
  • Laravel 中使用 FPDI 实现 PDF 骑缝章功能
  • almalinux9.6-4070显卡-ollama-qwen2.5-7b
  • 服务器之光:Nginx--核心配置详解及演练
  • 企业如何选择适合的高防服务器?