当前位置:首页 » 《我的小黑屋》 » 正文

[ C++ ] 一篇带你了解C++中隐藏的this指针

8 人参与  2024年04月03日 13:28  分类 : 《我的小黑屋》  评论

点击全文阅读


本篇文章我们将一起讨论在有趣的知识点--隐藏的this指针。本篇我们要使用到之前我们所学习到的C++类与对象(1),如果有各位小伙伴还不曾了解类与对象的简单思想,可以访问上篇博客:[ C++ ] 带你一篇了解什么是OOP(面向对象编程),什么是封装? -- 类与对象(上)

目录

1.this指针的引出

2.this指针的特性

3.练习一下

在之后的学习中,我们将认识一个新的类:日期类Date。正如我们所想的那样,传入一个日期,我们可以输出我们所输入的日期。

1.this指针的引出

那我们首先来看一下,这段代码会输出什么结果呢?

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();d2.Display();return 0;}

输出结果: 

我们首先可以通过汇编来看看,d1,d2调用的函数是否相同。

我们可以发现,最终打印的时候调用的Display()是同一个函数, 那么既然d1,d2调用的都是同一个函数,编译器如何知道d1是2022-5-11,d2是2022-5-12呢?Display()都访问的_year,_month,_day。而且去公共代码区访问的Display(),这是为什么呢?

这是因为C++在这段代码中做出手脚,C++在这里增加了一个this指针,这里是因为Display会增加一个this形参。C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成

在调用的时候也传的是各自的地址。这样就十分清晰明了了。这就是隐含的this指针

 

注意:我们不能显示的写出来,因为他是隐含的,我们不能抢了编译器的活。但是我们可以直接在类里面用。

2.this指针的特性

在真正的编译器中this指针的用const修饰的,this指针本身是不能被修改的,但是内容是可以修改的。并且我们是可以使用的

我们可以在类中打印一下this指针,并且我们在也同时打印一下d1和d2的地址,我们来看一下:

class Date{public:void Display(){        //使用this指针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(2022, 5, 11);d2.SetDate(2022, 5, 12);d1.Display();d2.Display();return 0;}

运行结果: 

 并且我们还能这样写,但是我们不能显示的写出Date* this。

 

我们接下来再看看this指针是不能修改的,大家看下面这个能过吗?答案肯定是不能的,因为this是被const修饰的,不能修改this指针的。

我们会发现 编译器也会报错:error C2106: “=”: 左操作数必须为左值

 this指针的特性总结:

1. this指针的类型:类类型* const。 2. 只能在“成员函数”的内部使用。 3. this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。 4. this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。

 

3.练习一下

(1)下面的程序的运行结果是? A.编译报错 B.运行崩溃 C.正常运行

class A{public:void Show(){cout << "show()" << endl;}private:int _a;};int main(){A* p = nullptr;p->Show();return 0;}

结果:C

原因:Show()函数是存在公共代码区中,编译的时候在公共代码区中找到这个函数,和普通的函数调用是一样的,只需要call函数地址就行。我们发现这里p是空指针,传过去的this指针只是接收了p的空指针,就类似于this指针被初始化为空指针。这是允许的。

 

(2)下面的程序的运行结果是? A.编译报错 B.运行崩溃 C.正常运行

class B{public:void PrintA(){cout << _a << endl;}private:int _a;};int main(){B* p2 = nullptr;p2->PrintA();return 0;}

结果:B

原因:此程序崩溃是在PrintA()中,会隐含一个this->_a,而this指针是一个空指针,访问this指针_a的位置,就要对空指针进行解引用,此时就会崩溃。我们也可通过调试观察到。

 (3)this指针是存在哪里的?

a.栈  b.堆  c.静态区  d.常量区

答案:a

解释:this指针是个形参,形参是在函数的栈桢里,在函数的栈桢里面的变量是属于栈中的。

有时编译器会使用寄存器对其进行优化,this指针会存在寄存器中。

 

 

(本篇完)

 


点击全文阅读


本文链接:http://zhangshiyu.com/post/90025.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1