一分钟搞懂什么是this指针(未涉及静态成员和函数)

前言

我们在学习类的过程中,一定听说过this指针,但是并不知道它跟谁相似,又有什么用途,所以接下来,让我们一起去学习this指针吧!

一、this指针的引入

我们先来看下面两段代码,它们输出的是什么?

#include <iostream>
using namespace std;
class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}void Printf(){cout << _year << '-' << _month << '-' << _day << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date date1(2023,11,14);date1.Printf();Date date2(2022,11,14);date2.Printf();return 0;
}

        我们可以明显的看到输出的结果,分别是我们输入的年月日,也就是说我们的类的成员变量并不是一个,而是多个,或者说是我们定义了几个实例化对象就有几个成员变量。

那为什么在C++中可以自动区分实例化对象的成员变量呢?他们是靠什么区分的呢?

其实这个就类似我们的C语言了,如果这个程序让C语言来写就是这样的:

        我们会发现,在C语言中要完成这样的操作,是需要提供我们这个实例化对象(date1,date2)的地址的,只有提供它们对应的地址,才可以完成专属的初始化,打印等操作。

#include <stdio.h>
typedef struct Date
{int _year;int _month;int _day;
}Date;
void Init(Date *pd,int year, int month, int day)
{pd->_year = year;pd->_month = month;pd->_day = day;
}
void Print(Date *pd)
{printf("%d-%d-%d\n",pd->_year,pd->_month,pd->_day);
}
int main()
{Date date1;Init(&date1,2023,11,14);Print(&date1);Date date2;Init(&date2,2022,11,14);Print(&date2);return 0;
}

        所以我们的C++其实也是根据传入每个实例化对象的地址,再用指针变量来接收的,只不过这部分操作是让编译器负责,不用咱们操心了,这就是大名鼎鼎的this指针。

二、this指针

        this指针就是存我们实例化对象的地址,之后根据每个实例化对象的地址来进行专属的操作的。我们的成员函数其实比我们看到的形参都多一个隐藏的参数this,所以正是基于这个原因this是一个关键字,在C++中被规定就是指向实例化对象的地址的。

它相当于下面这样:

        但是this指针不会在成员函数的形参中直接出现,这也就说明了,我们也不需要传实例化对象的地址,因为这都是编译器默认来完成的事情,我们做了就属于画蛇添足。

那this指针可以在哪里出现呢?

        this指针可以在成员函数的内部出现,这是被允许的。我们可以这么使用this,但是这也仅仅是帮助我们来理解为什么可以找到实例化对象对应的成员变量的,后期我们熟悉了,就不需要了。

后期我们会用到this,会给大家介绍(运算符重载

 Date(int year, int month, int day){this-> _year = year;this->_month = month;this-> _day = day;}void Printf(){cout << this-> _year << '-' << this-> _month << '-' << this-> _day << endl;}

三、this的常见问题

第一个问题:this可以被改变吗?

答案:不可以,默认this类型为:类类型 *const

解析:

因为我们的this指针,是实例化对象的地址,所以一般是不会改变它的,所以为了防止我们瞎玩,编译器默认this指针的类型是 类类型 *const this 

const 在 * 之前,是修饰的指针指向的对象,指针可以改,指向的对象不可以被修改

const在 * 之后,是修饰的指针本身,也就是指针不能修改,但是指向的内容可以修改

第二个问题:this可以在哪里使用?

答案:只在成员函数中使用

解析:

很明显,this是成员函数都有的一个形参,所以属于的是成员函数的作用域内,仅仅可以在自己的成员函数中使用

第三个问题:this存放在哪里?

答案:存放在函数栈帧上,也有的存放在寄存器上,主要看编译器

解析:

        因为this指针属于形参,所以就跟局部变量一样,是在函数栈帧上面开辟的空间,存在栈帧上的

        但是有的编译器是用寄存器存的,因为this会被编译器默认认为是经常使用的,又因为存在寄存器上很快,所以就存在寄存器上了。

        不同的编译器存放this指针的地方不同

第四个问题:this可以为空吗?

答案:单纯的对this赋空是不可以的,不过可以强转直接赋空,不过一般不进行这样的操作

解析:

我们看下面的代码来分析:首先是正常运行的

// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行#include <iostream>
using namespace std;
class A
{
public:void Print(){cout << "Print()" << endl;}
private:int _a;
};
int main()
{A* p = nullptr;p->Print();return 0;
}

        下面的代码我们定义了一个实例化对象的指针,指向的是空,但是这个是正常运行的,因为虽然我们的实例化对象的地址为空,可是在程序里我们访问的是成员函数,又因为成员函数的地址不存放在实例化对象里,所以根本没有空指针的解引用,是正常运行的;

但是如果是下面这样的代码,就会运行错误了

// 2.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行#include <iostream>
using namespace std;
class A
{
public:void Print(){cout << _a << endl;}
private:int _a;
};
int main()
{A* p = nullptr;p->Print();return 0;
}

        为什么不是编译错误,原因就是编译阶段只是检查我们的语法问题,无法识别空指针的解引用错误。运行错误就是因为在成员函数Print中,我们解引用了this指针,_a 相当于 this->_a 。所以这就是对空指针的解引用,原因是成员变量存放在实例化对象中

编译链接的博客在这里:http://t.csdnimg.cn/L6jFl

关于静态成员和函数与this指针

推荐大家看这篇博客http://t.csdnimg.cn/rEAtj

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/176088.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IDEA 2022创建Spring Boot项目

首先点击New Project 接下来&#xff1a; (1). 我们点击Spring Initializr来创建。 (2). 填写项目名称 (3). 选择路径 (4). 选择JDK------这里笔者选用jdk17。 (5). java选择对应版本即可。 (6). 其余选项如无特殊需求保持默认即可。 然后点击Next。 稍等一会&#xff0c…

【python后端】- 初识Django框架

Django入门 &#x1f604;生命不息&#xff0c;写作不止 &#x1f525; 继续踏上学习之路&#xff0c;学之分享笔记 &#x1f44a; 总有一天我也能像各位大佬一样 &#x1f31d;分享学习心得&#xff0c;欢迎指正&#xff0c;大家一起学习成长&#xff01; 文章目录 Django入门…

Programming Abstractions in C阅读笔记:p196

《Programming Abstractions in C》学习第63天&#xff0c;p196总结。涉及到编程之外的知识&#xff0c;依然是读起来很费劲&#xff0c;需要了解作者在书中提到的人物(Edouard Lucas)、地点(Benares)、神话传说(Brahma)等等。虽然深知自己做不到对人文知识&#xff0c;历史知识…

从0到0.01入门React | 009.精选 React 面试题

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

19 - 如何用协程来优化多线程业务?

近几年&#xff0c;国内很多互联网公司开始使用或转型 Go 语言&#xff0c;其中一个很重要的原因就是 Go 语言优越的性能表现&#xff0c;而这个优势与 Go 实现的轻量级线程 Goroutines&#xff08;协程 Coroutine&#xff09;不无关系。那么 Go 协程的实现与 Java 线程的实现有…

vue离线地图(瓦片)

最近公司要弄一个这样的离线地图&#xff0c;要求在图上打点画线之类的。折腾了几天&#xff0c;学习了三种方式&#xff1a; 1.拿到各省市区的经纬度json&#xff0c;通过echarts来制作&#xff0c;再套一个卫星图的地图背景 2.下载地图瓦片&#xff0c;再通过百度/高德的离线…

OpenGL_Learn11(光照)

目录 1. 光照 2. 环境光照 3. 漫反射光照 4. 代码实战 1. 光照 在OpenGL中主要分以下几个光照类型 环境光照(Ambient Lighting)&#xff1a;即使在黑暗的情况下&#xff0c;世界上通常也仍然有一些光亮&#xff08;月亮、远处的光&#xff09;&#xff0c;所以物体几乎永远不…

mac homebrew.mxcl.php@5.6.plist

今天启动php5.6时 遇到了一个问题 servers % brew services start php5.6 Bootstrap failed: 5: Input/output error Try re-running the command as root for richer errors. Error: Failure while executing; /bin/launchctl bootstrap gui/501 /Users/ssh/Library/LaunchAge…

部分背包问题【贪心算法】

部分背包问题是一种经典的贪心问题&#xff0c;物品可以取一部分&#xff0c;也就是可以随意拆分的物品。 算法思路&#xff1a; 用列表保存每个物品的价值及总重量、平均价值&#xff08;性价比&#xff09;。输入数据同时计算每种物品的平均价值。使用自定义的compare函数以…

【数据结构】堆(Heap):堆的实现、堆排序、TOP-K问题

目录 堆的概念及结构 ​编辑 堆的实现 实现堆的接口 堆的初始化 堆的打印 堆的销毁 获取最顶的根数据 交换 堆的插入&#xff08;插入最后&#xff09; 向上调整&#xff08;这次用的是小堆&#xff09; 堆的删除&#xff08;删除根&#xff09; 向下调整&#xff08;这次用的…

Redis05-集群方案

目录 Redis集群方案 主从复制 主从复制的基本原理 主从复制的工作流程 乐观复制 主从复制的优势 哨兵机制 哨兵的关键作用 服务状态监控 哨兵选举Master规则 分片集群 分片集群中的数据读写 数据写入 数据读取 一致性哈希和客户端分片 Redis集群方案 微服务时代…

从理论到实践:深度解读BIO、NIO、AIO的优缺点及使用场景

文章目录 BIO优缺点示例代码 NIO优缺点示例代码 AIO优缺点示例代码 总结 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 BIO、NIO和AIO是Java编程语言中用于处理输入输出&#xff08;IO…