C++之this指针
前言
C++中对象模型和this指针是面向对象编程中的重要概念。对象模型描述了对象在内存中的布局和行为,包括成员变量、成员函数的存储方式和访问权限。this指针是一个隐含的指针,指向当前对象的地址,用于在成员函数中引用当前对象的成员变量和成员函数。对象模型和this指针的理解和应用,对于深入理解C++的面向对象特性和实现细节至关重要。
提出问题
每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码。那么问题是:这一块代码是如何区分哪个对象调用自己的呢?
C++通过提供特殊的对象指针,this指针,解决上述问题。this指针指向被调用的成员函数所属的对象。this指针是隐含每一个非静态成员函数内的一种指针,this指针不需要定义,直接使用即可。
this指针的引出
引用自:【精选】[ C++ ] 一篇带你了解C++中隐藏的this指针_c++ this-CSDN博客
那我们首先来看一下,这段代码会输出什么结果呢?
#include<iostream>
using namespace std;class Date
{
public:void Display(){cout << _year << "-" << _month << "-" << _day << endl;}void SetDate(int year, int month, int day){_year = year;_month = month;_day = day;}
private:int _year; // 年int _month; // 月int _day; // 日
};
int main()
{Date d1, d2;d1.SetDate(2022, 5, 11);d2.SetDate(2022, 5, 12);d1.Display(); // 2022-5-11d2.Display(); // 2022-5-12return 0;
}
输出结果:
2022-5-11
2022-5-12
分析:
我们首先可以通过汇编来看看,d1,d2调用的函数是否相同。


我们可以发现,最终打印的时候调用的Display()(0A1500h)是同一个函数, 那么既然d1,d2调用的都是同一个函数,编译器如何知道d1是2022-5-11,d2是2022-5-12呢?Display()都访问的 _year,_month,_day。而且去公共代码区访问的Display(),这是为什么呢?
这是因为C++在这段代码中做了手脚,C++在这里增加了一个this指针,这里是因为 Display 会增加一个 this 形参。C++编译器给每个 “非静态的成员函数“ 增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问。只不过所有的操作对用户是隐藏的,即用户不需要来传递,编译器自动完成。
在调用的时候也传的是各自的地址,这样就十分清晰明了了。这就是隐含的this指针。



注意:我们不能显示的写出来,因为他是隐含的,我们不能抢了编译器的活。但是我们可以直接在类里面用。
将this指针存储的地址打印出来与类实例化后的对象地址作比较
#include<iostream>
using namespace std;class Date
{
public:void Display(){cout << this << endl;cout << _year << "-" << _month << "-" << _day << endl;}void SetDate(int year, int month, int day){_year = year;_month = month;_day = day;}
private:int _year; // 年int _month; // 月int _day; // 日
};
int main()
{Date d1, d2;cout << "d1的地址为:" << &d1 << endl;cout << "d2的地址为:" << &d2 << endl;d1.SetDate(2023, 1, 1);d2.SetDate(2023, 1, 2);cout << "d1调用Display函数时输出结果:" << endl;d1.Display();cout << "d2调用Display函数时输出结果:" << endl;d2.Display(); return 0;
}
输出结果:

this指针的用途
引用自:【C++漂流记】C++对象模型和this指针-CSDN博客
- 当形参和成员变量同名时,可用this指针来区分
- 在类的非静态成员函数中返回对象本身,可使用return *this
#include<iostream>
using namespace std;
class Person
{
public:Person(int age){//1、当形参和成员变量同名时,可用this指针来区分this->age = age;}Person& PersonAddPerson(Person p){this->age += p.age;//返回对象本身return *this;}int age;
};void test01()
{Person p1(10);cout << "p1.age = " << p1.age << endl;Person p2(10);p2.PersonAddPerson(p1).PersonAddPerson(p1).PersonAddPerson(p1);cout << "p2.age = " << p2.age << endl;
}int main() {test01();system("pause");return 0;
}
输出结果:

分析:
这段代码定义了一个Person类,其中包含一个构造函数和一个成员函数PersonAddPerson。test01函数创建了两个Person对象p1和p2,并测试了PersonAddPerson函数的功能。
在构造函数中,使用了this指针来区分形参和成员变量。this指针指向当前对象,可以通过this->age来访问成员变量age。
PersonAddPerson函数接受一个Person对象作为参数,将该对象的age加到当前对象的age上,并返回当前对象的引用。
在test01函数中,首先创建了一个age为10的Person对象p1,并输出其age值。然后创建了另一个age为10的Person对象p2,并连续三次调用PersonAddPerson函数,每次传入p1作为参数。最后输出p2的age值。
由于PersonAddPerson函数返回的是当前对象的引用,所以可以连续调用该函数。因此,p2的age值会依次增加30,最终输出为40。
空指针访问成员函数
C++中空指针也是可以调用成员函数的,但是也要注意有没有用到this指针。如果用到this指针,需要加以判断this指针是否为NULL,从而保证代码的鲁棒性。
示例:
#include<iostream>
using namespace std;//空指针访问成员函数
class Person {
public:void ShowClassName() {cout << "我是Person类!" << endl;}void ShowPerson() {if (this == NULL) {return;}cout << mAge << endl;}public:int mAge;
};void test01()
{Person* p = NULL;p->ShowClassName(); //空指针,可以调用成员函数p->ShowPerson(); //但是如果成员函数中用到了this指针,就不可以了
}int main() {test01();system("pause");return 0;
}
上述代码输出:
我是Person类!
分析:
这段代码定义了一个Person类,其中包含两个成员函数ShowClassName和ShowPerson,以及一个成员变量mAge。test01函数创建了一个空指针p,并尝试调用p的成员函数。
在C++中,空指针是指向任何对象的指针,因此可以通过空指针调用成员函数。在ShowClassName函数中,没有使用this指针,所以可以正常调用,输出结果为"我是Person类!"。
但是在ShowPerson函数中,使用了this指针来访问成员变量mAge。当空指针调用该函数时,this指针为NULL,因此访问成员变量时会出现错误。为了避免空指针访问,可以在函数体内通过判断this是否为NULL来提前返回,不执行后续代码。
总结:空指针可以调用成员函数,但是如果成员函数中使用了this指针来访问成员变量,需要注意空指针的处理,避免出现错误。
若将ShowPerson()函数中的if判断this指针是否为NULL语句去掉,则会抛出异常,如下图所示。

关于this指针的总结
关于this指针,有以下几点总结:
1)this指针指向当前对象,可以访问当前对象的所有成员变量。包括private、protected、public。
2)this指针是const指针,一切企图修改该指针的操作,如赋值(改变指向)、增减都是不允许的!
3)this指针只有在成员函数中才有定义。因此,在创建一个对象后,也不能通过对象使用this指针。所以,我们也无法知道一个对象的this指针的位置(只有在成员函数里才有this指针的位置)。当然,在成员函数里,你是可以知道this指针的位置的(可以this获得),也可以直接使用的。
4)只有创建对象后,this指针才有意义。
5)static静态成员函数不能使用this指针。原因静态成员函数属于类,而不属于某个对象,所以static静态成员函数压根就没有this指针。
6)this在成员函数的开始执行前构造的,在成员函数的执行结束后清除。至于如何清除的,由编译器实现,程序员不关心。this是通过函数参数的首参数来传递的。
部分参考自:
https://blog.csdn.net/Goforyouqp/article/details/133470535
https://blog.csdn.net/tr_ainiyangyang/article/details/125638721
【精选】[ C++ ] 一篇带你了解C++中隐藏的this指针_c++ this-CSDN博客
相关文章:
C++之this指针
前言 C中对象模型和this指针是面向对象编程中的重要概念。对象模型描述了对象在内存中的布局和行为,包括成员变量、成员函数的存储方式和访问权限。this指针是一个隐含的指针,指向当前对象的地址,用于在成员函数中引用当前对象的成员变量和成…...
大模型,重构自动驾驶
文|刘俊宏 编|王一粟 大模型如何重构自动驾驶?答案已经逐渐露出水面。 “在大数据、大模型为特征,以数据驱动为开发模式的自动驾驶3.0时代,自动驾驶大模型将在车端、云端上实现一个统一的端到端的平台管理。”毫末智…...
Jmeter执行接口自动化测试-如何初始化清空旧数据
需求分析: 每次执行完自动化测试,我们不会执行删除接口把数据删除,而需要留着手工测试,此时会导致下次执行测试有旧数据我们手工可能也会新增数据,导致下次执行自动化测试有旧数据 下面介绍两种清空数据的方法 一、通过…...
dashboard报错 错误:无法获取网络列表、dashboard报错 错误:无法获取云主机列表 解决流程
文章目录 错误说明dashboard上报错底层命令报错查看日志message日志httpd报错日志错误日志分析开始解决测试底层命令dashboard错误说明 dashboard上报错 首先,dashboard上无论是管理员还是其他项目,均无法获取云主机和网络信息,具体报错如下...
C语言中的3种注释方法
C语言中的3种注释方法 2021年8月28日星期六席锦 在用C语言编程时,常用的注释方式有如下几种: (1)单行注释 // … (2)多行注释 /* … */ (3)条件编译注释 #if 0…#endif (1)(2)在入门教程中比较常见。 对于(1) 【单行注释 // …】,注释只能显示…...
20款VS Code实用插件推荐
前言: VS Code是一个轻量级但功能强大的源代码编辑器,轻量级指的是下载下来的VS Code其实就是一个简单的编辑器,强大指的是支持多种语言的环境插件拓展,也正是因为这种支持插件式安装环境开发让VS Code成为了开发语言工具中的霸主…...
攻防世界web篇-robots
打开网址后,发现是一个空白页面的网页 但是,这个题目是robots,所以就联想到robots.txt这个目录,于是我就试了一下 注意:这里有个php的文件,这个应该就是一个目录文件 当输入后,直接回车&#…...
6 个可解锁部分 GPT-4 功能的 Chrome 扩展(无需支付 ChatGPT Plus 费用)
在过去的几个月里,我广泛探索了 ChatGPT 的所有可用插件。在此期间,我发现了一些令人惊叹的插件,它们改进了我使用 ChatGPT 的方式,但现在,我将透露一些您需要了解的内容。 借助 Chrome 扩展程序,所有 Chat…...
centos 7.9 安装sshpass
1.作用 sshpass是一个用于非交互式SSH密码验证的实用程序。它可以用于自动输入密码以进行SSH登录,从而简化了自动化脚本和批处理作业中的SSH连接过程。 sshpass命令可以与ssh命令一起使用,通过在命令行中提供密码参数来执行远程命令。以下是一个示例命…...
CompletableFuture多任务异步,获取返回值,汇总结果
线程池异步的基础知识 详情见:https://blog.csdn.net/sinat_32502451/article/details/133039624 线程池执行多任务,获取返回值 线程池的 submit()方法,可以提交任务,并返回 Future接口。 而 future.get(),可以获取…...
Linux上Qt和Opencv人脸识别项目学习路线(嵌入式/C++)
本文将介绍Linux人脸识别项目的开发流程, 只作简略介绍所需知识点及大致流程。 注:若需详细教程请联系作者(见文末)。 一、基本开发环境搭建 1.1 安装虚拟机Ubuntu 虚拟机采用的是VMware,需要下载VMware安装包、ubuntu系统镜像…...
spring 源码阅读之@Configuration解析
Configuration解析 Configuration注解用于标识一个类是配置类,用于声明和组织Bean定义,首先Configuration本身也是一个Component,在其注解定义上标有Component Target(ElementType.TYPE) Retention(RetentionPolicy.RUNTIME) Documented Co…...
Java Web 33道面试题汇总
更多面试合集在:https://javaxiaobear.cn 1、http 的长连接和短连接? HTTP 协议有 HTTP/1.0 版本和 HTTP/1.1 版本。HTTP1.1 默认保持长连接(HTTP persistent connection,也翻译为持久连接),数据传输完成了保持 TCP 连接不断开(不发 RST 包、不四次握手),等待在同域名…...
设计模式记录
设计模式 抽象工厂模式单例模式要实现一个单例,需要关注的点有下面几个: 抽象工厂模式 PHP工厂模式是一种可扩展、可维护和可重复使用的方法,旨在提供通用接口,用于创建对象。工厂模式的主要组成部分包括抽象工厂、具体工厂、抽象产品和具体产…...
Java设计模式之亨元模式(Flyweight Pattern)
亨元模式(Flyweight Pattern)是一种结构型设计模式,旨在通过共享对象来最大限度地减少内存使用和提高性能。该模式适用于需要创建大量相似对象的情况,其中许多对象具有相同的状态。通过共享相同的状态,亨元模式可以减少…...
正点原子嵌入式linux驱动开发——Linux中断
不管是单片机裸机实验还是Linux下的驱动实验,中断都是频繁使用的功能,在裸机中使用中断需要做一大堆的工作,比如配置寄存器,使能IRQ等等。但是Linux内核提供了完善的中断框架,只需要申请中断,然后注册中断处…...
基于Jaya优化算法的电力系统最优潮流研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
Write-Ahead Log(PostgreSQL 14 Internals翻译版)
日志 如果发生停电、操作系统错误或数据库服务器崩溃等故障,RAM中的所有内容都将丢失;只有写入磁盘的数据才会被保留。要在故障后启动服务器,必须恢复数据一致性。如果磁盘本身已损坏,则必须通过备份恢复来解决相同的问题。 理论…...
CUDA 学习记录
1.关于volatile: 对于文章中这个函数, __global__ void reduceUnrollWarps8 (int *g_idata, int *g_odata, unsigned int n) {// set thread IDunsigned int tid threadIdx.x;unsigned int idx blockIdx.x * blockDim.x * 8 threadIdx.x;// convert…...
【Java 进阶篇】深入了解 Bootstrap 按钮和图标
按钮和图标在网页设计中扮演着重要的角色,它们是用户与网站或应用程序交互的关键元素之一。Bootstrap 是一个流行的前端框架,提供了丰富的按钮样式和图标库,使开发者能够轻松创建吸引人的界面。在本文中,我们将深入探讨 Bootstrap…...
相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...
MySQL 部分重点知识篇
一、数据库对象 1. 主键 定义 :主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 :确保数据的完整性,便于数据的查询和管理。 示例 :在学生信息表中,学号可以作为主键ÿ…...
R 语言科研绘图第 55 期 --- 网络图-聚类
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能
1. 开发环境准备 安装DevEco Studio 3.1: 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK 项目配置: // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...
CppCon 2015 学习:REFLECTION TECHNIQUES IN C++
关于 Reflection(反射) 这个概念,总结一下: Reflection(反射)是什么? 反射是对类型的自我检查能力(Introspection) 可以查看类的成员变量、成员函数等信息。反射允许枚…...
RLHF vs RLVR:对齐学习中的两种强化方式详解
在语言模型对齐(alignment)中,强化学习(RL)是一种重要的策略。而其中两种典型形式——RLHF(Reinforcement Learning with Human Feedback) 与 RLVR(Reinforcement Learning with Ver…...
