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

深入理解 C++ 内存模型与对象底层机制:this 指针的秘密

很多初学者在学习 C 面向对象时脑海里都会有一个疑问“既然每个对象都有自己的变量那类里面的函数是放在哪里的如果函数是共享的它怎么知道我现在操作的是哪个对象的数据”今天我们就从 C 的四大内存分区说起扒开编译器的外衣彻底搞懂对象与this指针的底层逻辑。一、 C 的四大内存分区在 C 程序运行时操作系统会为程序分配内存并将内存划分为四个主要区域。理解这四个区是理解面向对象底层逻辑的前提代码区Code Segment存放程序执行的二进制机器指令包括你写的所有函数、类的方法。这一块是只读且共享的。全局/数据区Data Segment存放全局变量、静态变量static以及常量。程序结束后由系统释放。栈区Stack存放函数内部的局部变量、形参。由编译器自动分配和释放速度快但空间有限。我们平时直接ABC a;创建的对象就存在这里。堆区Heap由程序员手动分配和释放的内存使用new/delete。空间大但速度相对较慢。代码验证对象存在哪#include iostream using namespace std; int global_var 10; // 存放在【全局/数据区】 class ABC { public: int n; }; int main() { ABC a; // 局部对象 a存放在【栈区】 ABC* b new ABC(); // b 本身是一个指针变量存放在【栈区】但它指向的 ABC 对象存放在【堆区】 cout 全局变量地址 (数据区): global_var endl; cout 局部对象 a 地址 (栈区): a endl; cout 动态对象 b 地址 (堆区): b endl; delete b; return 0; }二、 对象的内存占用只有数据没有代码每创建一个对象系统只会在内存如栈区中为这个对象的数据成员变量分配空间而绝不会为函数分配空间。类中声明的函数包括普通函数、构造函数、析构函数全部被编译成指令统一存放在代码区。无论你创建了 1 个对象还是 1000 个对象这些函数在内存中永远只有一份被所有对象共享使用。代码验证用sizeof证明函数不占对象内存#include iostream using namespace std; class EmptyClass {}; class DataClass { public: int n; // 占 4 字节 }; class FuncClass { public: int n; // 占 4 字节 // 下面写了一堆函数 FuncClass() {} ~FuncClass() {} void doSomething1() {} void doSomething2() {} }; int main() { // 空类通常占 1 字节为了在内存中有独一无二的地址 cout EmptyClass 大小: sizeof(EmptyClass) endl; cout DataClass 大小: sizeof(DataClass) endl; // 输出 4 // FuncClass 里面多了那么多函数大小依然是 4 字节 // 这证明了函数根本不存在于对象内部而是剥离出去存放在了代码区。 cout FuncClass 大小: sizeof(FuncClass) endl; return 0; }三、 this 指针既然函数只有一份存在代码区供所有对象共同调用。那么问题来了 当执行obj1.set_n(10)和obj2.set_n(20)时同一份代码是怎么知道应该去修改obj1的内存还是去修改obj2的内存呢答案就是C 编译器在底层通过隐藏的this指针做了手脚1. 编译器的“暗箱操作”当你在 C 中写下这样的代码class ABC { public: int n; void set_n(int val) { n val; // 你以为就这么简单 } }; int main() { ABC a; a.set_n(100); return 0; }在底层例如g编译时编译器会把这段 C 面向对象代码翻译成类似 C 语言的面向过程代码。翻译步骤如下给函数增加一个隐藏的参数编译器会悄悄把调用该函数的对象的地址传进去。这个隐藏参数的类型是ABC* const this一个常量指针指向当前对象指针本身不能改变指向。在函数内部替换变量名把类内部所有的成员变量前面强制加上this-。在调用处传递地址把你写的a.set_n(100)翻译成set_n(a, 100)。2. 揭开伪装底层的真实面貌上面那段代码在编译器眼里的真实模样其实是这样的伪代码// 1. 结构体只保留数据 struct ABC { int n; }; // 2. 函数被剥离出来并被强行塞入了一个 this 指针作为第一个参数 // 注意 this 的类型是类名* const void ABC_set_n(ABC* const this, int val) { this-n val; // 3. 内部自动加上 this- } int main() { ABC a; // 4. 调用函数时编译器偷偷把对象 a 的地址a传给了 this 指针 ABC_set_n(a, 100); return 0; }3. this 指针的本质与限制通过上面的底层翻译我们可以总结出this指针的几个核心特征this本质上是一个隐藏的函数形参它并不存在于对象内部不占用对象的存储空间。它的精确类型是类类型* const。这意味着在函数内部你可以改变对象的值如this-n 10但你绝对不能改变this指针的指向比如不能写this another_obj。因为它是隐藏形参所以只有在非静态non-static成员函数内部才能使用this指针。

相关文章:

深入理解 C++ 内存模型与对象底层机制:this 指针的秘密

很多初学者在学习 C 面向对象时,脑海里都会有一个疑问:“既然每个对象都有自己的变量,那类里面的函数是放在哪里的?如果函数是共享的,它怎么知道我现在操作的是哪个对象的数据?”今天,我们就从 …...

102-MIC最大信息系数回归预测模型(MATLAB实现)|特征筛选算法|含完整可运行代码

温馨提示:文末有联系方式什么是MIC最大信息系数 MIC(Maximal Information Coefficient)是一种用于量化变量间线性或非线性关联强度的统计指标,基于互信息理论设计,广泛应用于机器学习前的特征重要性评估与筛选环节。MI…...

Python 3.12 Key Words - 01 - Summary

Python 3.12 Key Words:引言:什么是关键字? 在 Python 中,关键字(Keyword) 是语言语法的一部分,是 Python 语言中预先保留的具有特殊含义的标识符。它们像建筑中的钢筋水泥,构成了程…...

如何利用SQL存储过程处理大数据_利用分页批处理降低压力

...

Laravel Blade 中高效筛选并限制关联分类数据的实践指南

本文讲解如何在 Laravel 中避免在 Blade 模板中嵌套循环与字符串解析,转而使用数据库层的 WHERE FIND_IN_SET() 配合 limit() 实现精准、高效的数据筛选与分页控制。 本文讲解如何在 laravel 中避免在 blade 模板中嵌套循环与字符串解析,转而使用数…...

Redis怎样设计企业级备份策略_结合全量RDB与增量AOF实现多级数据保护

全量备份应选RDB;因其文件小、恢复快,适合作为每日基线备份,而AOF仅宜作为增量补丁,不可替代RDB承担全量角色。全量备份选 RDB 还是 AOF?得看恢复速度和磁盘压力RDB 是快照式备份,save 或 bgsave 生成的 du…...

HTML函数在超频CPU上更流畅吗_超频对HTML函数影响【技巧】

HTML函数不受CPU超频影响,其执行速度由浏览器引擎、事件循环和网络栈决定;超频仅提升Web Workers中计算密集型任务性能,却可能降低计时精度并暴露竞态问题。HTML函数根本不受CPU超频影响超频CPU不会让 document.getElementById、setTimeout 或…...

CSS 中实现同类型兄弟元素悬停联动效果(如所有红色行同时高亮)

本文介绍如何利用 css :has() 伪类实现“悬停任一同类元素时,所有同类型兄弟元素同步响应样式变化”,无需 javascript,纯 css 可控,适用于分组高亮等交互场景。 本文介绍如何利用 css :has() 伪类实现“悬停任一同类元素时&a…...

Angular 转 React 避坑指南:10个高频错误

一、为什么要写这篇文章做过 React 转 Angular 迁移的同学都知道——光看文档是不够的。文档告诉你 API 怎么用,但不会告诉你哪些"习惯性写法"在新框架里会悄悄出错,还不报错。本文来自真实迁移经历,整理了 6 类高频踩坑场景&#…...

从Overleaf回归本地:我为什么选择TeXLive+WinEdt搭建更高效的LaTeX写作环境?

从Overleaf回归本地:为什么TeXLiveWinEdt能打造更高效的LaTeX工作流? 当你在深夜赶论文时突然遭遇Overleaf服务器崩溃,或是需要自定义某个冷门宏包却受限于在线环境权限,那种无力感足以让任何LaTeX用户重新思考工具链的选择。作为…...

LeagueAkari英雄联盟工具包:10个提升游戏体验的终极技巧

LeagueAkari英雄联盟工具包:10个提升游戏体验的终极技巧 【免费下载链接】League-Toolkit An all-in-one toolkit for LeagueClient. Gathering power 🚀. 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit 你是否厌倦了繁琐的英雄联…...

别再写一堆if了!Mybatis动态SQL的choose/when/otherwise标签,5分钟搞定多条件分支

告别if嵌套噩梦:MyBatis动态SQL的choose/when/otherwise实战指南 在电商后台开发中,我们经常遇到这样的场景:需要根据不同的订单状态或用户等级查询不同的数据。传统的做法是使用一连串的if标签,结果XML文件变得臃肿不堪&#xff…...

Vivado HLS实战避坑指南:从C代码到可用的IP核,我踩过的那些坑

Vivado HLS实战避坑指南:从C代码到可用的IP核,我踩过的那些坑 第一次用Vivado HLS把C代码变成FPGA上的IP核时,那种兴奋感至今难忘。但很快我就发现,从"能跑通Demo"到"做出稳定可用的IP"之间,横亘着…...

从SOT-23到SOT-963:手把手教你识别和选用那些长得像的SMD晶体管封装

从SOT-23到SOT-963:手把手教你识别和选用那些长得像的SMD晶体管封装 在物联网设备和小型化电子产品设计中,SMD晶体管封装的选择往往让人头疼。那些看似相同的微型封装,实际上在尺寸、引脚排列和散热性能上存在微妙差异。一位资深工程师曾告诉…...

别再死记硬背Next数组了!用‘最长相等前后缀’这个核心概念,5分钟彻底搞懂KMP

从几何视角彻底理解KMP算法:Next数组的本质是字符串的自相似性 每次看到KMP算法中那个神秘的Next数组,总有种面对黑盒的感觉——明明代码只有几行,背后的逻辑却像被施了魔法。今天我们不谈公式推导,换个视角用"最长相等前后缀…...

【代码】基于交替方向乘子法(admm)的微电网分布式低碳优化运行策略matlab-yalmip-cplex/gurobi

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…...

如何解决多线图中线条颜色不渲染(仅标记和提示框显示颜色)的问题

多线图中线条显示为黑色而标记点和工具提示却正常显示设定颜色,通常是因第三方 css 或 javascript 库意外覆盖了图表库的样式或破坏了其渲染逻辑所致。 多线图中线条显示为黑色而标记点和工具提示却正常显示设定颜色,通常是因第三方 css 或 javascr…...

CSS如何消除图片下方多余间隙_设置display-block改变盒模型

图片下方空白源于img默认inline导致的基线对齐&#xff1b;display:block最直接有效&#xff0c;vertical-align:middle等有兼容性与场景限制&#xff0c;font-size:0或line-height:0副作用大。图片下方空白是行内元素的基线对齐导致的默认情况下 <img> 是行内元素&#…...

自己做agent项目时,为什么工具和提示词写完之后总要重构再重构

最近有朋友来问我&#xff0c;他们团队做内部agent代理项目&#xff0c;工具写了十几个&#xff0c;能跑起来了&#xff0c;但后来想加权限没地方加&#xff0c;agent中断之后也不知道怎么恢复状态&#xff0c;最后只好停下来把工具全部重写了一遍&#xff01; 他们花了一个小…...

逆向YouTube Shorts接口:我是如何用Java和Protobuf搞定短视频列表解析的

逆向解析YouTube Shorts接口&#xff1a;Java与Protobuf实战指南 在移动应用逆向工程领域&#xff0c;Google系产品的接口分析向来以高复杂度著称。本文将分享如何突破层层技术障碍&#xff0c;从零开始解析YouTube Shorts短视频列表接口的全过程。不同于常见的API调用教程&…...

SAP财务凭证增强实战:利用BADI_ACC_DOCUMENT和CI_COBL为BAPI_ACC_DOCUMENT_POST扩展自定义字段

SAP财务凭证增强实战&#xff1a;从需求分析到稳定部署的全流程设计 在SAP标准财务模块实施过程中&#xff0c;业务需求的个性化往往超出标准功能的覆盖范围。当企业需要为会计凭证添加反记账标识、自定义记账码等特殊字段时&#xff0c;标准的BAPI_ACC_DOCUMENT_POST接口就显得…...

Akagi麻将AI助手:30天从新手到高手的终极免费指南

Akagi麻将AI助手&#xff1a;30天从新手到高手的终极免费指南 【免费下载链接】Akagi 支持雀魂、天鳳、麻雀一番街、天月麻將&#xff0c;能夠使用自定義的AI模型實時分析對局並給出建議&#xff0c;內建Mortal AI作為示例。 Supports Majsoul, Tenhou, Riichi City, Amatsuki,…...

SpringBoot+Vue教务管理系统源码+论文

代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339; 分享万套开题报告任务书答辩PPT模板 作者完整代码目录供你选择&#xff1a; 《SpringBoot网站项目》1800套 《SSM网站项目》1500套 《小程序项目》1600套 《APP项目》1500套 《Python网站项目》…...

如何配置Oracle 19c Data Pump目录_数据泵导入导出的环境准备

必须先创建DIRECTORY对象并授权&#xff1a;CREATE OR REPLACE DIRECTORY dpump_dir AS /u01/app/oracle/dpdump; GRANT READ,WRITE ON DIRECTORY dpump_dir TO scott; 且Oracle进程需有目录读写权限。怎么创建 Data Pump 目录对象&#xff08;DIRECTORY&#xff09;oracle dat…...

SpringBoot项目整合FISCO BCOS 2.9.1 SDK:从WeBASE-Front导出合约到Java调用的保姆级避坑指南

SpringBoot项目整合FISCO BCOS 2.9.1 SDK实战&#xff1a;从合约导出到Java调用的全流程解析 当Java开发者首次尝试将区块链能力整合到现有SpringBoot项目中时&#xff0c;往往会遇到一系列意料之外的挑战。本文将以一个典型的企业级资产管理系统为背景&#xff0c;详细拆解从W…...

C语言宏定义续行符踩坑实录:手把手教你解决‘backslash and newline separated by space’警告

C语言宏定义续行符的隐秘陷阱&#xff1a;从警告解析到工程级解决方案 第一次在CLion里看到backslash and newline separated by space这个警告时&#xff0c;我盯着那个无辜的反斜杠看了足足三分钟。作为一个刚接触C语言宏编程的开发者&#xff0c;这个看似简单的格式问题背后…...

UniApp实战:精准控制微信小程序iOS端滚动行为,告别橡皮筋回弹

1. 为什么iOS橡皮筋效果让人又爱又恨 第一次用UniApp开发微信小程序时&#xff0c;我就被iOS这个特性整懵了。明明在安卓机上运行正常的页面&#xff0c;到了iPhone上就变成了"橡皮泥"——随便一拉就能扯出大片空白。后来才知道&#xff0c;这正是iOS引以为傲的橡皮筋…...

HarmonyOS布局避坑指南:为什么你的Column和Row总对不齐?

HarmonyOS布局避坑指南&#xff1a;为什么你的Column和Row总对不齐&#xff1f; 在HarmonyOS应用开发中&#xff0c;布局是构建用户界面的基础。然而&#xff0c;许多开发者在实际项目中常常遇到Column和Row组件对不齐的问题&#xff0c;导致界面显示效果不尽如人意。本文将深入…...

别再只盯着K-Means了!用sklearn的轮廓系数(silhouette_score)帮你选出最佳聚类算法

用轮廓系数为聚类算法打分&#xff1a;从K-Means到DBSCAN的科学选择指南 当面对一堆未标注的数据时&#xff0c;很多人的第一反应是直接套用K-Means算法——这就像拿到食材只会做炒饭一样。但真实世界的数据分布千奇百怪&#xff0c;有的像瑞士奶酪布满空洞&#xff08;适合DBS…...

JavaScript 中的 setTimeout 是否依赖系统时钟?

settimeout 的延迟计时基于浏览器内部的高精度单调时钟&#xff08;如 performance.now() 所依赖的机制&#xff09;&#xff0c;而非操作系统本地时间&#xff1b;因此修改系统时间不会影响其倒计时行为&#xff0c;但页面休眠、cpu 节流或事件循环阻塞会导致实际触发延迟。 …...