【C/C++】深度探索c++对象模型_笔记
1. 对象内存布局
(1) 普通类(无虚函数)
- 成员变量排列:按声明顺序存储,但编译器会根据内存对齐规则插入填充字节(padding)。
class Simple {char a; // 1字节(偏移0)int b; // 4字节(偏移4,因对齐跳过1-3字节)double c; // 8字节(偏移8) }; // 总大小:1 + 3(padding) +4 +8 = 16字节(64位系统)
- 成员函数:独立于对象存储,编译时转换为普通函数,隐式添加
this
指针参数。
(2) 含虚函数的类
- 虚表指针(vptr):对象头部插入一个指针,指向类的虚函数表(vtable)。
- 虚函数表(vtable):一个函数指针数组,按虚函数声明顺序存储地址。
内存布局:class Base { public:virtual void func1() {} // vtable[0]virtual void func2() {} // vtable[1]int data; // 偏移8(假设vptr占8字节) };
[vptr][data]
vtable内容:[&Base::func1, &Base::func2]
2. 虚函数与动态绑定
(1) 多态实现流程
- 对象构造时:编译器在构造函数中插入代码,将
vptr
指向当前类的虚表。 - 函数调用时:通过
vptr
找到虚表,再根据函数声明顺序索引到具体函数地址。
底层伪代码:Base* obj = new Derived(); obj->func1(); // 实际调用 Derived::func1()
mov rax, [obj] ; 获取vptr call [rax + 0] ; 调用vtable[0]处的函数
(2) 覆盖与扩展
- 派生类覆盖虚函数:替换基类虚表中对应的函数指针。
- 派生类新增虚函数:在虚表末尾追加新条目。
class Derived : public Base { public:void func1() override {} // 替换Base的vtable[0]virtual void func3() {} // 追加到vtable[2] };
3. 继承机制
(1) 单继承
- 内存布局:基类成员在前,派生类成员在后。
class Base { int a; }; class Derived : public Base { int b; }; // 布局:[Base::a][Derived::b]
- 虚函数表:派生类虚表继承基类虚表条目并覆盖或扩展。
(2) 多重继承
-
内存布局:按继承顺序排列各基类子对象,每个多态基类有自己的
vptr
。class Base1 { virtual void f1() {} }; class Base2 { virtual void f2() {} }; class Derived : public Base1, public Base2 {};
布局:
[Base1 vptr][Base1 data][Base2 vptr][Base2 data][Derived data]
-
指针调整:当将
Derived*
转换为Base2*
时,编译器自动调整指针偏移。Derived d; Base2* pb2 = &d; // 指针实际指向 Base2 子对象起始地址
(3) 虚继承(解决菱形继承)
-
虚基类子对象共享:所有虚继承路径共享同一个基类实例。
class A { int a; }; class B : virtual public A { int b; }; class C : virtual public A { int c; }; class D : public B, public C { int d; };
布局:
B
部分:[B vptr][B::b][虚基类A的偏移信息]
C
部分:[C vptr][C::c][虚基类A的偏移信息]
D::d
- 共享的
A::a
(位于对象尾部)
-
虚基类表(vbtl):存储虚基类子对象的偏移量,供构造函数初始化时使用。
4. 构造函数与析构函数
(1) 构造过程
- 隐式操作:编译器在构造函数中自动插入以下代码:
- 调用基类构造函数。
- 初始化
vptr
(确保多态正确)。 - 初始化虚基类(若存在)。
- 执行成员变量的初始化列表。
- 执行用户编写的构造函数体。
(2) 虚析构函数
- 必要性:若基类析构函数非虚,通过基类指针删除派生类对象会导致资源泄漏(派生类析构函数不被调用)。
- 实现:虚析构函数在虚表中占用一个条目,确保动态绑定到实际对象的析构函数。
5. 函数调用与 this
指针
(1) 成员函数调用
- 成员函数被编译为普通函数,首个参数为隐式
this
指针。// 源代码 void MyClass::func(int x) { ... }// 编译后伪代码 void MyClass_func(MyClass* this, int x) { ... }
(2) 虚函数调用
- 通过
vptr
和vtable
动态解析函数地址,等价于:// obj->virtual_func() 的底层行为 (*(obj->vptr[n]))(obj); // n为虚函数在表中的索引
6. 内存对齐与优化
- 对齐规则:变量地址通常是其类型大小(sizeof)的整数倍。例如:
int
(4字节)的地址需是4的倍数。double
(8字节)的地址需是8的倍数。
- 手动调整对齐:
#pragma pack(1) // 设置1字节对齐(禁用填充) struct Unaligned {char a; // 偏移0int b; // 偏移1(正常情况下会填充到偏移4) }; #pragma pack() // 恢复默认对齐
7. 模板与异常处理的影响
(1) 模板实例化
- 每个模板实例化会生成独立的代码,可能导致代码膨胀。例如:
template<typename T> class Box { T data; }; Box<int> a; // 生成 Box<int> 的代码 Box<double> b;// 生成 Box<double> 的代码
(2) 异常处理
- 栈展开(Stack Unwinding):抛出异常时,析构局部对象需要依赖虚函数表信息(若涉及多态)。
总结
《深度探索C++对象模型》揭示了C++语法背后的底层实现逻辑,理解这些机制可帮助开发者:
- 优化性能:通过内存布局调整减少缓存未命中(Cache Miss)。
- 调试复杂问题:如多态失效、内存对齐错误、菱形继承问题。
- 避免未定义行为:如错误转换指针导致的内存访问错误。
- 设计高效类:权衡虚函数开销与灵活性。
相关文章:
【C/C++】深度探索c++对象模型_笔记
1. 对象内存布局 (1) 普通类(无虚函数) 成员变量排列:按声明顺序存储,但编译器会根据内存对齐规则插入填充字节(padding)。class Simple {char a; // 1字节(偏移0)int b; …...

RustDesk:开源电脑远程控制软件
RustDesk:开源电脑远程控制软件 RustDesk:开源电脑远程控制软件一、RustDesk 简介二、下载教程2.1 桌面版下载2.2 Android 版下载 三、安装教程3.1 桌面版安装 四、功能讲解4.1 远程控制4.2 文件传输4.3 安全可靠4.4 自定义服务器 五、RustDesk技术架构解…...

[操作系统] 策略模式进行日志模块设计
文章目录 [toc]一、什么是设计模式?二、日志系统的基本构成三、策略模式在日志系统中的落地实现✦ 1. 策略基类 LogStrategy✦ 2. 具体策略类▸ 控制台输出:ConsoleLogStrategy▸ 文件输出:FileLogStrategy 四、日志等级枚举与转换函数五、日…...
掌握Docker Commit:轻松创建自定义镜像
使用 docker commit 命令可以通过对现有容器进行修改来创建新的镜像。-a 选项用于指定作者信息,-m 选项用于添加提交信息。以下是具体步骤: 启动并修改容器 启动一个容器并进行必要的修改。例如,启动一个 Ubuntu 容器并安装一些软件包&…...

MoonBit正式入驻GitCode!AI时代的编程语言新星,开启高性能开发新纪元
在AI与编程语言深度交融的今天,开发者们正见证一场技术生产力的革命。由IDEA研究院基础软件中心倾力打造的MoonBit(月兔)编程语言,自2023年横空出世以来,凭借高性能、低延迟、轻量化的特性,迅速成为全球开发…...
命令行快速上传文件到SFTP服务器(附参考示例)
一、SFTP基础命令格式 更新参数后的标准命令格式为: sftp -P [端口号] [用户名][服务器IP]:[远程路径] <<< $put [本地文件路径]二、新参数实例解析 使用新连接参数的完整命令示例: sftp -P 30033 test_jigou_sftp121.199.64.216:/download…...

关于vue学习的经常性错误
目录 常见问题: 1关于引用本地下载es6模块文件,报404错误 2 使用createApp函数后没有调用mount函数挂载到浏览器 3 在mount函数中,忘记引用插值表达式所在标签的定位符如 标签选择器,类选择器等 4在直接使用Vue3函数时&#…...
数据结构与算法-双向链表专题
目录 一. 双向链表的结构 二.双向链表的使用 2.1 创建节点 2.2 初始化 2.3 打印 2.4 尾插 2.5 头插 2.6 尾删 2.7 头删 2.8 在指定位置pos之后插入数据 2.9 查找数据 2.10 删除pos位置的节点 2.11 销毁链表 一. 双向链表的结构 在List.h的头文件中对链表的结构进行创建 #prag…...
AtCoder Beginner Contest 403
再来一场atCoder,这一场简直血虐,让你回忆起了审题的重要性 A - Odd Position Sum 思路:题意很简单,求一个数组奇数位上数字和。很简单的问题,但你如果不仔细审题,就会浪费大量的时间 /* Author Owen_Q…...

关于 Golang GC 机制的一些细节:什么是根对象?GC 机制的触发时机?
文章目录 关于 Golang GC 机制的一些细节:什么是根对象?GC 机制的触发时机?简要回顾 Golang GC 三色标记法的工作流程什么是根对象?GC 的触发时机? 关于 Golang GC 机制的一些细节:什么是根对象?…...

Python笔记:c++内嵌python,c++主窗口如何传递给脚本中的QDialog,使用的是pybind11
1. 问题描述 用的是python 3.8.20, qt版本使用的是5.15.2, PySide的版本是5.15.2, pybind11的版本为2.13.6 网上说在python脚本中直接用PySide2自带的QWinWidget,如from PySide2.QtWinExtras import QWinWidget,但我用的版本中说没有QWinWidget&#x…...
在Ubuntu24.04中配置开源直线特征提取软件DeepLSD
在Ubuntu24.04中配置开源直线特征提取软件DeepLSD 本文提供在Ubuntu24.04中配置开源直线特征提取软件DeepLSD的基础环境配置、列出需要修改的文件内容,以及报错解决方案集锦。 基础的编译安装环境 python3.8.12CUDA12gcc/g 9.5(系统自带的g-13版本太新…...

C++效率掌握之STL库:map set底层剖析及迭代器万字详解
文章目录 1.map、set的基本结构2.map、set模拟实现2.1 初步定义2.2 仿函数实现2.3 Find功能实现2.4 迭代器初步功能实现2.4.1 运算符重载2.4.2 --运算符重载2.4.3 *运算符重载2.4.4 ->运算符重载2.4.5 !运算符重载2.4.6 begin()2.4.7 end() 2.5 迭代器进阶功能实现2.5.1 set…...

新三消示例项目《Gem Hunter》中的光照和视觉效果
《Gem Hunter》是 Unity 的全新官方示例项目,展示了如何在 Unity 2022 LTS 使用通用渲染管线 (URP) 打造抢眼的光效和视效,让 2D 益智/三消游戏在竞争中脱颖而出。 下载示例项目及其说明文档。准备潜入清澈湛蓝的海水中探寻财富吧,因为那里到…...
通用软件项目技术报告 - 导读III
现在,我们正式进入报告的第六个主要领域:6. 领域六:与第三方服务/API 集成 (含 LLM API)。 连接: 在现代软件开发中,很少有应用程序是完全孤立的。我们经常需要与各种外部的第三方服务或 API 进行集成,以利用它们提供的特定功能(如支付处理、地图服务、社交媒体登录、云…...
代码随想录训练营第二十三天| 572.另一颗树的子树 104.二叉树的最大深度 559.N叉树的最大深度 111.二叉树的最小深度
572.另一颗树的子树: 状态:已做出 思路: 这道题目当时第一时间不是想到利用100.相同的树思路来解决,而是先想到了使用kmp,不过这个题目官方题解确实是有kmp解法的,我使用的暴力解法,kmp的大致思…...

单向循环链表C语言实现实现(全)
#include<stdio.h> #include<stdlib.h> #define TRUE 1 #define FASLE 0//定义宏标识判断是否成功 typedef struct Node {int data;struct Node* next; }Node;Node* InitList() {Node* list (Node*)malloc(sizeof(Node));list->data 0;//创建节点保存datalist…...

【AI大模型】赋能【传统业务】
在数字化转型的浪潮下,传统业务流程(如通知公告管理、文档处理等)仍依赖人工操作,面临效率低、成本高、易出错等问题。以企业通知公告为例,从内容撰写、摘要提炼到信息分发,需耗费大量人力与时间࿰…...
Clion内置宏$PROJECT_DIR$等
CLion 内置宏 文章目录 CLion 内置宏通用路径相关宏路径相对化宏 官方文档地址: https://www.jetbrains.com/help/clion/built-in-macros.html 通用路径相关宏 宏名称含义说明示例$WORKSPACE_DIR$当前项目所属的工作区根目录路径。/home/user/workspace$PROJECT_D…...

团结引擎开源车模 Sample 发布:光照渲染优化 动态交互全面体验升级
光照、材质与交互效果的精细控制,通常意味着复杂的技术挑战,但借助 Shader Graph 14.1.0(已内置在团结引擎官方 1.5.0 版本中),这一切都变得简单易用。通过最新团结引擎官方车模 Sample,开发者能切身感受到全新光照优化与编辑功能…...
hghac8008漏洞扫描处理
文章目录 环境文档用途详细信息相关文档 环境 系统平台:Linux x86-64 Red Hat Enterprise Linux 7 版本:4.5.10 文档用途 本文只要用于在客户提出hghac8008端口漏洞时,如何进行漏洞处理,本文章的方法已经应用于浪潮云ÿ…...
PyQt5教程:QComboBox下拉列表框的全面解析与实战应用
QComboBox概述 QComboBox是PyQt5中一个集按钮和下拉选项于一体的控件,通常被称为下拉列表框或组合框。它允许用户从预定义的选项列表中选择一个值,是GUI开发中最常用的输入控件之一。 主要特点: 紧凑的界面设计,节省屏幕空间提…...
GAN简读
Abstract 我们提出了一个通过同时训练两个模型的对抗过程来评估生成模型的新框架:一个生成模型 G G G用来捕捉数据特征,还有一个用于估计这个样本是来自训练样本还是 G G G的概率的判别模型 D D D, G G G的训练过程是最大化 D D D犯错的概率。这个框架就相当于一个minimax tw…...

精准测量“双雄会”:品致与麦科信光隔离探头谁更胜一筹
在电子技术飞速发展的当下,每一次精准测量都如同为科技大厦添砖加瓦。光隔离探头作为测量领域的关键角色,能有效隔绝电气干扰,保障测量安全与精准。在众多品牌中,PINTECH品致与麦科信的光隔离探头脱颖而出,成为工程师们…...

NSSCTF [HNCTF 2022 WEEK4]
题解前的吐槽:紧拖慢拖还是在前段时间开始学了堆的UAF(虽然栈还没学明白,都好难[擦汗]),一直觉得学的懵懵懂懂,不太敢发题解,这题算是入堆题后一段时间的学习成果,有什么问题各位师傅可以提出来,…...
Step1
项目 SchedulerSim 已搭建完成 ✅ ⸻ ✅ 你现在拥有的: • 🔧 两种调度器(Round Robin SJF) • 📦 模拟进程类 Process • 🧱 清晰结构:OOP 风格 便于扩展 • ✍️ 主函数已演示调度器运行效…...

tornado_登录页面(案例)
目录 1.基础知识编辑 2.脚手架(模版) 3.登录流程图(processon) 4.登录表单 4.1后(返回值)任何值:username/password (4.1.1)app.py (4.1.2ÿ…...

YOLOv12模型部署(保姆级)
一、下载YOLOv12源码 1.通过网盘分享的文件:YOLOv12 链接: https://pan.baidu.com/s/12-DEbWx1Gu7dC-ehIIaKtQ 提取码: sgqy (网盘下载) 2.进入github克隆YOLOv12源码包 二、安装Anaconda/pycharm 点击获取官网链接(anaconda) 点击获取…...

BGP实验练习1
需求: 要求五台路由器的环回地址均可以相互访问 需求分析: 1.图中存在五个路由器 AR1、AR2、AR3、AR4、AR5,分属不同自治系统(AS),AR1 在 AS 100,AR2 - AR4 在 AS 200,AR5 在 AS …...
Three.js知识框架
一、Three.js 基础概念 1. Three.js 简介 是什么? 基于 WebGL 的 3D JavaScript 库,用于在浏览器中渲染 3D 场景。 核心优势 简化 WebGL 的复杂 API,提供高层封装。 跨平台(支持桌面和移动端)。 适用场景 3D 可视…...