4.3 C++对象模型和this指针
4.3 C++对象模型和this指针
4.3.1 成员变量和成员函数分开存储
在C++中,类内的成员变量和成员函数分开存储
只有非静态成员变量才属于类的对象上
#include <iostream>class Person {
public:Person() {mA = 0;} //非静态成员变量占对象空间int mA;//静态成员变量不占对象空间static int mB;//函数也不占对象空间,所有函数共享一个函数实例void func() {std::cout << "mA:" << this->mA << std::endl;} //静态成员函数也不占对象空间static void sfunc() {}
};int main() {//实例化一个对象为p1Person p1;std::cout << "Person:"<<sizeof(Person) << std::endl;std::cout << "p1:" << sizeof(p1) << std::endl;return 0;
}
运行结果如下:

4.3.2 this指针概念
通过4.3.1我们知道在C++中成员变量和成员函数是分开存储的
每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码
那么问题是:这一块代码是如何区分那个对象调用自己的呢?
c++通过提供特殊的对象指针,this指针,解决上述问题。
this指针指向被调用的成员函数所属的对象
this指针是隐含每一个非静态成员函数内的一种指针
this指针不需要定义,直接使用即可
this指针是一个常量指针,可以看做const type * this ,指针的指向不能修改,this = NULL这样是错的。
this指针的用途:
当形参和成员变量同名时,可用this指针来区分
在类的非静态成员函数中返回对象本身,可使用return *this
#include <iostream>class Person {
public:Person(int age) {//1 使用this区分形参和成员变量this->age = age;} Person& PersonAddPerson(Person p) {this->age += p.age;//2 返回对象本身,this为指针,所以加上*return *this;} //定义一个成员变量,属性为publicint age;
};void test01()
{ //实例化一个对象为p1,会调用有参构造函数Person p1(10);//打印p1.age的结果std::cout << "p1.age:" << p1.age << std::endl;//实例化一个对象为p2Person p2(12);//p2.PersonAddPerson(p1)这是使用p2对象调用成员函数PersonAddPerson(p1),//成员函数返回值是对象p2,然后再次调用成员函数p2.PersonAddPerson(p1).PersonAddPerson(p1).PersonAddPerson(p1);std::cout << "p2.age:" << p2.age << std::endl;}int main() {test01();return 0;
}
运行结果如下:

#include <iostream>class MyClass {
public:void printAddress() {std::cout << "Address of the current object: " << this << std::endl;}void modifyObject() {// 下面的语句是非法的,会导致编译错误// this = nullptr; // Error: assignment of read-only parameter 'this'// 修改成员变量是合法的data = 42;}private:int data;
};int main() {MyClass obj;// 调用成员函数,显示对象地址obj.printAddress();// 调用修改对象的函数obj.modifyObject();return 0;
}
4.3.3 空指针访问成员函数
C++中空指针也是可以调用成员函数的,但是也要注意有没有用到this指针
如果用到this指针,需要加以判断保证代码的健壮性
示例:
#include <iostream>class Person {
public:void ShowClassName() {std::cout << "Person类" << std::endl;} void ShowPerson() {if(this == NULL)return ;std::cout << "age:" << age << std::endl;} int age;};void test01()
{ //创建一个对象指针Person* p1 = NULL;//使用对象指针调用成员函数p1->ShowClassName();//使用对象指针调用成员函数,成员函数使用了this指针,空对象指针就使用不了 p1->ShowPerson();}int main() {test01();return 0;
}
执行结果如下:

成员函数去掉this判断部分
#include <iostream>class Person {
public:void ShowClassName() {std::cout << "Person类" << std::endl;} void ShowPerson() {/*if(this == NULL)return ;*/std::cout << "age:" << age << std::endl;} int age;};void test01()
{ //创建一个对象指针Person* p1 = NULL;//使用对象指针调用成员函数p1->ShowClassName();//使用对象指针调用成员函数,成员函数使用了this指针,空对象指针就使用不了p1->ShowPerson();}int main() {test01();return 0;
}
再次编译执行结果如下

对于上面出现的错误做一个解释,
代码中,如果去掉了 if(this == NULL) 的检查,并试图在一个空指针上调用 ShowPerson 函数,程序会尝试通过一个空指针来访问 age 成员变量。对空指针进行解引用是一种未定义的行为,通常会导致段错误。
具体步骤如下:
- 声明一个空指针,例如
Person* nullPointer = nullptr;。 - 尝试在这个空指针上调用一个成员函数:
nullPointer->ShowPerson();。 - 在
ShowPerson函数内部,尝试通过this->age访问age成员变量。 - 由于
this是一个空指针,尝试访问this->age会导致段错误。
4.3.4 const修饰成员函数
常函数:
成员函数后加const后我们称为这个函数为常函数
常函数内不可以修改成员属性
成员属性声明时加关键字mutable后,在常函数中依然可以修改
常对象:
声明对象前加const称该对象为常对象
常对象只能调用常函数
const修饰成员函数
#include <iostream>class Person {
public://默认构造函数Person() {p_a = 0;p_b = 0;} void ShowPerson() {//隐含在每个成员函数内部都有一个this指针,this是一个常量指针//this = NULL; 常量指针的内容不能修改this->p_a = 10;//对于常量指针的指向的内容可以修改 } void ShowPerson2() const {//隐含在每个成员函数内部都有一个this指针,this是一个常量指针//this = NULL; 常量指针的内容不能修改//const修饰成员函数,表示指针指向的内存空间的数据不能修改,除了mutable修饰的变量//this->p_a = 20;//p_b变量被mutable修饰,可以修改this->p_b = 100;//常函数中变量不能修改//p_a = 12;//使用mutable修改的变量可以修改p_b = 22; } public:int p_a;mutable int p_b;};void test01()
{ //创建一个对象,会调用默认构造函数Person p1;//查看变量p_a和p_b的值,调用构造函数后值都为0std::cout << "p_a:" << p1.p_a << " p_b:" << p1.p_b << std::endl;//使用对象调用成员函数p1.ShowPerson();//查看此时变量p_a和p_b的值,p_a会变为10,p_b为0std::cout << "p_a:" << p1.p_a << " p_b:" << p1.p_b << std::endl;//使用对象调用常量成员函数p1.ShowPerson2();//查看此时变量p_a和p_b的值,p_a会为10,p_b为22std::cout << "p_a:" << p1.p_a << " p_b:" << p1.p_b << std::endl;}int main() {test01();return 0;
}
运行结果如下图:

const修饰对象
#include <iostream>class Person {
public://默认构造函数Person() {p_a = 0;p_b = 0;} void ShowPerson() {//隐含在每个成员函数内部都有一个this指针,this是一个常量指针//this = NULL; 常量指针的内容不能修改this->p_a = 10;//对于常量指针的指向的内容可以修改 } void ShowPerson2() const {//隐含在每个成员函数内部都有一个this指针,this是一个常量指针//this = NULL; 常量指针的内容不能修改//const修饰成员函数,表示指针指向的内存空间的数据不能修改,除了mutable修饰的变量//this->p_a = 20;//p_b变量被mutable修饰,可以修改this->p_b = 100;//常函数中变量不能修改//p_a = 12;//使用mutable修改的变量可以修改p_b = 22; } public:int p_a;mutable int p_b;};void test01()
{ //创建一个常量对象p1,会调用默认构造函数const Person p1;//1 常量对象不能修改成员变量的值//p1.p_a = 33;//可以修改被mutable修饰的变量值p1.p_b = 11;//可以访问成员变量的值std::cout << "p_a:" << p1.p_a << std::endl;std::cout << "p_b:" << p1.p_b << std::endl;//2 常量对象访问成员函数,只能访问常函数//ShowPerson是非常函数,常量对象不能访问//p1.ShowPerson();//访问常函数p1.ShowPerson2();std::cout << "p_a:" << p1.p_a << " p_b:" << p1.p_b << std::endl;}int main() {test01();return 0;
}
运行结果如下:

相关文章:
4.3 C++对象模型和this指针
4.3 C对象模型和this指针 4.3.1 成员变量和成员函数分开存储 在C中,类内的成员变量和成员函数分开存储 只有非静态成员变量才属于类的对象上 #include <iostream>class Person { public:Person() {mA 0;} //非静态成员变量占对象空间int mA;//静态成员变量…...
计算机网络——计算机网络的概述(一)
前言: 面对马上的期末考试,也为了以后找工作,需要掌握更多的知识,而且我们现实生活中也已经离不开计算机,更离不开计算机网络,今天开始我们就对计算机网络的知识进行一个简单的学习与记录。 目录 一、什么…...
基于多反应堆的高并发服务器【C/C++/Reactor】(中)ChannelMap 模块的实现
(三)ChannelMap 模块的实现 这个模块其实就是为Channel来服务的,前面讲了Channel这个结构体里边它封装了文件描述符。假如说我们得到了某一个文件描述符,需要基于这个文件描述符进行它对应的事件处理,那怎么办呢&…...
微信小程序实现一个音乐播放器的功能
微信小程序实现一个音乐播放器的功能 要求代码实现wxml 文件wxss 文件js文件 解析 要求 1.页面包含一个音乐列表,点击列表中的音乐可以播放对应的音乐。 2.播放中的音乐在列表中有标识,并且可以暂停或继续播放。 3.显示当前音乐的播放进度和总时长&#…...
算法基础之表达整数的奇怪方式
表达整数的奇怪方式 中国剩余定理: 求M 所有m之积 然后Mi M / mi x 如下图 满足要求 扩展中国剩余定理 找到x **使得x mod mi ai**成立 对于每两个式子 都可以推出①式 即 用扩展欧几里得算法 可以算出k1,-k2和m2–m1 判无解 : 若**(m2–m1) % d ! 0** 说明该等式无解 …...
WEB 3D技术 three.js 设置图像随窗口大小变化而变化
本文 我们来讲讲我们图层适应窗口变化的效果 可能这样说有点笼统 那么 自适应应该大家更熟悉 就是 当我们窗口发生变化说 做一些界面调整比例 例如 我们这样一个i项目界面 我们打开 F12 明显有一部分被挡住了 那么 我们可以刷新 这样是正常了 但是 我们将F12关掉 给F12的…...
实战案例:缓存不一致问题的解决(redis+本地缓存caffine)
一.问题引入 目前在写项目的时候,在B端查看文章,A端修改文章。为了增加效率,以及防止堆内存溢出,在B端选择本地缓存文章的方案。但是目前出现了A端对文章修改之后,B端读的还是旧数据,出现了缓存不一致的问…...
【开源CDP】市场增长未来的探索,开源CDP带来的技术崛起与变革
数字化趋势之下,数据成了企业竞争的核心资源,不管是公域还是私域,网络俨然成了品牌打响市场的一线战场,然而,在这场数字战役里,许多企业不得不面临一个共同问题:数据零散、分散、平台众多、无法…...
第11章 GUI Page423~424 步骤六 支持文字,使用菜单,对话框输入文字
运行效果: 点击OK,然后再窗口上按住左键,拖动鼠标 关键代码: 新增头文件和成员,新增私有成员_text 成员初始化 为菜单项MenuItemText添加响应函数 新增创建TextItem()的代码...
【Qt】Qt Creator 警告: Unused parameter ‘xxx‘
1. 问题 Qt开发中,有些函数参数没有使用,会报Unused parameter xxx警告,这个警告不影响代码正常运行。 2. 屏蔽这个警告的方法 2.1 方法1 函数中添加 Q_UNUSED(arg); TestClass::TestClass(QObject *parent) {Q_UNUSED(parent); }2.2 方…...
「Vue3面试系列」Vue3.0性能提升主要是通过哪几方面体现的?
文章目录 一、编译阶段diff算法优化静态提升事件监听缓存SSR优化 二、源码体积三、响应式系统参考文献 一、编译阶段 回顾Vue2,我们知道每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把用到的数据property记录为依赖,当依赖发…...
网络结构模式
一、C/S结构 服务器 - 客户机,即 Client - Server ( C/S )结构。 C/S 结构通常采取两层结构。服务器负责数据的 管理,客户机负责完成与用户的交互任务。客户机是因特网上访问别人信息的机器,服务器则是提 供信息供人…...
IIC及OLED实验
I2C (Inter-Integrated Circuit): I2C 是一种用于在芯片之间进行短距离数字通信的串行通信协议。它允许多个设备通过两根导线(一根数据线 SDA 和一根时钟线 SCL)进行通信。I2C 常常用于嵌入式系统中连接传感器、存储器、显示屏和其他外设。 数据线和时钟…...
day6 力扣公共前缀--go实现---对字符串的一些思考
今日份知识: curl -x 指定方法名 请求的url -d 请求体body里面的内容 //curl命令 curl -x Get 127.0.0.1:8080/add/user -d jinlicurl如果不指定方法,默认使用get方法,在go里面,get方法到底可以不可以把内容数据写在body里面传…...
27.Java程序设计-基于Springboot的在线考试系统小程序设计与实现
1. 引言 随着数字化教育的发展,在线考试系统成为教育领域的一项重要工具。本论文旨在介绍一个基于Spring Boot框架的在线考试系统小程序的设计与实现。在线考试系统的开发旨在提高考试的效率,简化管理流程,并提供更好的用户体验。 2. 系统设…...
Redis可视化工具Redis Desktop Manager mac功能特色
Redis Desktop Manager mac是一款非常实用的Redis可视化工具。RDM支持SSL / TLS加密,SSH隧道,基于SSH隧道的TLS,为您提供了一个易于使用的GUI,可以访问您的Redis数据库并执行一些基本操作:将键视为树,CRUD键…...
【C++】揭开运算符重载的神秘面纱
目录 一、引言 优点 二、介绍 1.定义 2.语法 三、示例 1.加法运算符重载 2.一元运算符重载 3.友元函数 4.流插入和流提取 5.自增自减运算符 总结 一、引言 何为运算符重载?运算符重载,是C中的一项强大特性,赋予了程序员在自定义类…...
竞赛保研 基于LSTM的天气预测 - 时间序列预测
0 前言 🔥 优质竞赛项目系列,今天要分享的是 机器学习大数据分析项目 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐! 🧿 更多资料, 项目分享: https://gitee.com/dancheng-senior/po…...
前端常用的开发工具
前端常用的开发工具🔖 文章目录 前端常用的开发工具🔖1. Snipaste--截图工具2. ScreenToGif--gif图片录制3. Typora--Markdown编辑器4. notepad--文本代码编辑器5. uTools--多功能工具6. EV录屏--录屏软件7. Xmind--思维导图8. Apifox -- 接口调试9. Tor…...
鸿蒙开发语言介绍--ArkTS
1.编程语言介绍 ArkTS是HarmonyOS主力应用开发语言。它在TypeScript (简称TS)的基础上,匹配ArkUI框架,扩展了声明式UI、状态管理等相应的能力,让开发者以更简洁、更自然的方式开发跨端应用。 2.TypeScript简介 自行补充TypeScript知识吧。h…...
eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...
手机平板能效生态设计指令EU 2023/1670标准解读
手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读,综合法规核心要求、最新修正及企业合规要点: 一、法规背景与目标 生效与强制时间 发布于2023年8月31日(OJ公报&…...
什么是VR全景技术
VR全景技术,全称为虚拟现实全景技术,是通过计算机图像模拟生成三维空间中的虚拟世界,使用户能够在该虚拟世界中进行全方位、无死角的观察和交互的技术。VR全景技术模拟人在真实空间中的视觉体验,结合图文、3D、音视频等多媒体元素…...
