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

简介: 一分钟搞懂什么是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;
}

02ad56fc893547eabbdd861fedb944f4.png

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

二、this指针


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

它相当于下面这样:

e6106ec725a84cec953b6cd51e334209.png    但是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指针出现的场景


答案:目前作者学习用到this的地方是在运算符重载这里,等以后学习更多知识会更新的


例子:


我们以日期类为准,想比较日期的大小,肯定是不能直接比较的,因为日期类是一个自定义类型,所以我们要用到运算符重载,在大于,等于这里我们就正常比较,但是到了小于,我们可以复用前面的,因为小于就是不大于,不等于,但是如何找到当前的日期呢?因为我们知道成员函数都有一个隐藏的参数--this指针,所以我们可以通过this指针来找到比较的其中一位,另一位就是another,比较如图:

class Date
{
public:
    //运算符重载 >
    bool operator>(const Date& another) const;
    //运算符重载 ==
    bool operator==(const Date& another) const;
    //运算符重载 <
private:
    int _month;
    int _day;
    int _year;
};
//    //运算符重载 >
bool Date::operator>(const Date &another) const
{
    if(_year > another._year)
        return true;
    else if(_year == another._year && _month > another._month)
        return true;
    else if(_year == another._year && _month == another._month && _day > another._day)
        return true;
    else
        return false;
}
//    //运算符重载 ==
bool Date::operator==(const Date &another) const
{
    return _year == another._year && _month == another._month && _day == another._day;
}
//    //运算符重载 <
bool Date::operator<(const Date &another) const
{
    return !(*this > another || *this == another);
}
相关文章
|
2月前
|
C++
定义和使用指向函数的指针变量
定义和使用指向函数的指针变量
15 1
|
2月前
|
C语言
【C语言】指针进阶之sizeof和strlen函数的对比
【C语言】指针进阶之sizeof和strlen函数的对比
|
27天前
|
搜索推荐 C语言 C++
【C指针(五)】6种转移表实现整合longjmp()/setjmp()函数和qsort函数详解分析&&模拟实现3
【C指针(五)】6种转移表实现整合longjmp()/setjmp()函数和qsort函数详解分析&&模拟实现
|
8天前
|
存储 C语言
指针数组作为main函数的形参
指针数组作为main函数的形参
13 0
|
15天前
|
存储 编译器 C++
【C++成长记】C++入门 | 类和对象(上) |类的作用域、类的实例化、类的对象大小的计算、类成员函数的this指针
【C++成长记】C++入门 | 类和对象(上) |类的作用域、类的实例化、类的对象大小的计算、类成员函数的this指针
|
22天前
|
存储 编译器 程序员
【C++】类和对象①(什么是面向对象 | 类的定义 | 类的访问限定符及封装 | 类的作用域和实例化 | 类对象的存储方式 | this指针)
【C++】类和对象①(什么是面向对象 | 类的定义 | 类的访问限定符及封装 | 类的作用域和实例化 | 类对象的存储方式 | this指针)
|
2月前
|
存储 编译器 C语言
【c++】类和对象(二)this指针
朋友们大家好,本节内容来到类和对象第二篇,本篇文章会带领大家了解this指针
【c++】类和对象(二)this指针
|
2月前
|
存储 编译器 C语言
【C++练级之路】【Lv.2】类和对象(上)(类的定义,访问限定符,类的作用域,类的实例化,类的对象大小,this指针)
【C++练级之路】【Lv.2】类和对象(上)(类的定义,访问限定符,类的作用域,类的实例化,类的对象大小,this指针)
|
2月前
|
安全 C语言 C++
字符指针做函数参数
字符指针做函数参数
10 1
|
2月前
|
安全 C语言
字符指针作函数参数的深入探索
在C语言编程中,字符指针是一个重要的概念,尤其在处理字符串和文本数据时。当我们将字符指针作为函数参数时,可以实现多种灵活和高效的操作。本文将深入探讨字符指针作为函数参数的应用,并通过代码示例加以说明。
15 1