this指针!
我们知道,类中的成员函数是有专门的存放区:公共代码区
,这也就意味着我们进行函数调用的时候用的都是一个函数。
既然如此那么我们进行成员函数调用时,编译器是如何知道要操作的对象是什么呢
d1.Print();
d2.Print();
C++中通过引入this
指针解决该问题,即:
void Print()
{
cout << _year << endl;
}
// 底层
void Print(Date* this)
{
cout << this->_year << endl;
}
C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”的操作,都是通过该指针去访问。
只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
我们可以将C++中调用成员函数的代码翻译为C语言代码:
例如:我们有如下C++代码
class Car
{
public:
int m_price; // 成员变量
void SetPrice(int p) // 成员函数
{
m_price = p;
}
};
int main()
{
Car car;
car.SetPrice(20000); // 给car对象m_price成员变量赋值
return 0;
}
如何进行翻译呢?
先来看结果。
struct Car
{
int price;
};
void SetPrice(struct Car* this, int p)
{
this->price = p;
}
int main()
{
struct Car car;
SetPrice( &car, 20000); // 给car结构体的price变量赋值
return 0;
}
接下来解释一下为什么这么翻译
注意:
我们只是更形象的类比的理解,不要过分深究,毕竟C语言和C++还是有不同的
我们知道C语言中可没有class关键字,但是有struct关键字
故:
struct Car
{
int price;
};
但是C语言成员函数的概念,更没有所谓的公共代码区,所以我们选择将成员函数类比为全局函数。
void SetPrice(struct Car* this, int p)
{
//从这里的this指针我们就可以看到这种做法我们其实是经常用的
//比如栈的压栈啦等等
//stackpush(stack* ps, int val);
this->price = p;
}
最后就是main函数中的调用:、
int main()
{
struct Car car;
SetPrice( &car, 20000);
return 0;
}
这种视角博主是从知乎这看到的,觉得对于this指针的理解比较有用,大家可以读一读原文
(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,
按照将程序翻译为C语言的理解:p->Show()
类似为Show(nullptr)
,传递一个空指针是不影响,毕竟我们并不访问
(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,
按照将程序翻译为C语言的理解:p->Show()
类似为Show(nullptr)
,传递一个空指针是不影响,但是我们对其进行解引用操作就有问题了(解引用空指针就像踹开警察的门)
(3)this指针是存在哪里的?
a.栈 b.堆 c.静态区 d.常量区
答案:a
this指针是个形参,形参是在函数的栈桢里,在函数的栈桢里面的变量是属于栈中的。
有时编译器会使用寄存器对其进行优化,this指针会存在寄存器中。