💐 🌸 🌷 🍀 🌹 🌻 🌺 🍁 🍃 🍂 🌿 🍄🍝 🍛 🍤
📃个人主页 :阿然成长日记 👈点击可跳转
📆 个人专栏: 🔹数据结构与算法🔹C语言进阶
🚩 不能则学,不知则问,耻于问人,决无长进
🍭 🍯 🍎 🍏 🍊 🍋 🍒 🍇 🍉 🍓 🍑 🍈 🍌 🍐 🍍
文章目录
- 一、this指针引入
- 1.引入
- 2.分析
- 3.图示
- 二、 this指针存在哪里?
- 三、 案例分析
一、this指针引入
1.引入
#include<iostream>
using namespace std;
class Data
{
public:void Init(int year,int month,int day){_year = year;_month = month;_day = day;}void print(){cout << _year << ":" << _month << ":" << _day << endl;}
private:int _year;int _month;int _day;
};int main()
{
//创建Data的对象1Data d1;d1.Init(1999, 1, 1);
//创建Data的对象2Data d2;d2.Init(2023, 1, 1);
//调用print函数d1.print();d2.print();return 0;
}
打印结果:
2.分析
上面代码运行结果中,为什么两个对象调用同一个函数能打印出不同的日期呢?或者说同一个函数如何做到结果不同呢?
简单说是通过C++的一个关键字this来实现的。
上面代码着编译后,就成了如下:
#include<iostream>
using namespace std;
class Data
{
public:void Init(int year,int month,int day){_year = year;_month = month;_day = day;}void print(Data* this){cout << this->_year << ":" << this->_month << ":" << this->_day << endl;}
private:int _year;int _month;int _day;
};int main()
{
//创建Data的对象1Data d1;d1.Init(1999, 1, 1);
//创建Data的对象2Data d2;d2.Init(2023, 1, 1);
//调用print函数d1.print(&d1);d2.print(&d2);return 0;
}
当不同对象调用print函数时,其实在底层是传了一个Data*类型的指针this。
void print(Data* this){cout << this->_year << ":" << this->_month << ":" << this->_day << endl;}
> 如下图所示:
其实底层还是和C语言函数调用一样,也需要传参,只不过C++的编译器为我们默默做了这些事情,让我们用起来更方便。但是,不能显示的去写出this的相关实参和形参,需要注意的是在类中可以使用this->。
3.图示
this本质是一个形参,哪个对象调用他,就指向哪个对象。
二、 this指针存在哪里?
下图是代码在vs2019编译器下执行的汇编语句
。
当执行d1.Init(1999, 1, 1);时,先是将三个实参进行压栈。其实实参应该有4
个,还有一个隐藏的this指针
。
(1)000426EF push 1
(2)000426F1 push 1
(2)000426F3 push 7CFh
通过这一句(4)000426F8 lea ecx,[d1]
我们可以清晰的看到this指针在vs编译器下,是存到了寄存器( ecx)。
其实,this指针存在的位置一般是在栈帧上,不同的编译器有所不同,例如vs2019就是存在寄存器上。
因为this指针,占用内存小并且需要频繁使用,所以,将它放到寄存器里能大大提升运行效率。
三、 案例分析
下面代码会出现问题吗?
class A
{
public:
void Print()
{
cout << "Print()" << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Print();
return 0;
}
前提知识
- p指针为空,相当于this指针为空。
- 成员变量存储在对象中
- 成员函数没有存储在对象中
- p->Print();说明调用的是A类中的成员函数
调用print函数与this指针无关,只有访问成员变量时才会使用到this。
因为函数是在编译链接的时候找的,上一篇详细讲过对象的存储方式中讲过,函数的调用是通过公共区域的函数表查找修饰后的函数名【因为C++支持重载,所以需要对函数名 进行特殊的修饰】来进行查找。
所以,代码运行正常。
看下面代码:
class A
{
public:
void PrintA()
{
cout<<_a<<endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->PrintA();
return 0;
}
printA函数中使用了成员变量,需要使用this指针,但此时this指针为空。
所以,运行崩溃!