一文詳解C++中隱含的this指針
一、this指針的引出
我們先來定義一個(gè)日期類Date,下面這段代碼執(zhí)行的結(jié)果是什么呢?
class Date
{
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()
{
Date d1, d2;
d1.Init(2022, 5, 11);
d2.Init(2022, 5, 12);
d1.print();
d2.print();
return 0;
}
可以看到分別打印出了兩個(gè)日期,它是怎么知道改打印哪個(gè)的?

我們來分析一下,先看一下匯編代碼,看一看

- 我們看到上面的代碼是調(diào)用的同一個(gè)函數(shù),那么編譯器是如何知道那兩個(gè)日期的?
- 其實(shí)C++里有一個(gè)隱形的this指針,在微軟的官方文檔也有說明
- 在使用函數(shù)的時(shí)候其實(shí)里面傳了一個(gè)地址,然后有一個(gè)隱的this指針來接收
原形是這樣:


- 那為什么這里報(bào)錯(cuò)了呢?
- 因?yàn)椴槐匾獙?,這個(gè)是隱含的~~,我們可以直接在類里面使用
二、this指針的特性
剛剛上面也給你看了原形,細(xì)心的烙鐵已經(jīng)發(fā)現(xiàn)了,這個(gè)this指針是有一個(gè)const修飾的,而且這個(gè)const是在*的右邊

這里的const修飾

- 到這里就得出的this本身是不被修改的,但是做指向的值是可以被修改
- 我們可以在類中打印一下this指針的地址,再打印一下d1和d2的地址,我們來看一下:

- 得到結(jié)果就是this指針指向一個(gè)指向當(dāng)前對象的指針
- 我們還可以下面這樣,是不會(huì)報(bào)錯(cuò)的,但是不能向上面直接在形參就寫上

特點(diǎn):
1、形參和實(shí)參的位置,我們不能顯示寫
2、函數(shù)內(nèi)部可以使用
最后總結(jié)一下:
- this指針的類型:類型 *const,即成員函數(shù)中,不能給this指針賦值。
- 只能在“成員函數(shù)”的內(nèi)部使用this指針本質(zhì)上是“成員函數(shù)”的形參,當(dāng)對象調(diào)用成員函數(shù)時(shí),將對象地址作為實(shí)參傳遞給this形參。所以對象中不存儲(chǔ)this指針。
- this指針是“成員函數(shù)”第一個(gè)隱含的指針形參,一般情況由編譯器通過ecx寄存器自動(dòng)傳遞,不需要用戶傳遞
【面試題】
this指針存在哪里?
a、堆 b、棧 c、靜態(tài)區(qū) d、常量區(qū) e、對象里面
- 首先排除
e,因?yàn)槲覀冎溃谒泐惱锏?strong>對象的時(shí)候是沒有算this指針的大小,所以排除e - C++的const變量不是在常量區(qū),可以看到這兩個(gè)地址是挨著的

那么什么在常量區(qū)呢?是const修飾的值在常量區(qū),這個(gè)指針變量在棧區(qū),指向了這個(gè)常量區(qū)的字符串的首字符,所以d也就排除

- c就更不可能了,static和全局的才在靜態(tài)區(qū)
- a也可以排除,因?yàn)閙alloc的才在堆,這里不是malloc,所以排除
- 最后就是在棧上,因?yàn)?strong>是一個(gè)形參(有些編譯比如vs可能會(huì)用寄存器存儲(chǔ))。不同的編譯器放在不同的位置,可能是棧,也可能是寄存器,(VC++編譯器是放在ECX中,其它編譯器有可能不同,也就是成員函數(shù)的其它參數(shù)正常都是存放在棧中。而this指針參數(shù)則是存放在寄存器中。)
- 打開匯編我們也可以看到這里的lea就是load effective address【加載有效地址】,是存在ecx的值加載到 [d1] 里

this指針可以為空嗎?
下面我們來看兩道題來解決這個(gè)問題的答案~
第一道:下面程序編譯運(yùn)行結(jié)果是? A、編譯報(bào)錯(cuò) B、運(yùn)行崩潰 C、正常運(yùn)行
class A
{
public:
void Print()
{
cout << "Print()" << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Print();
return 0;
}
已經(jīng)完美運(yùn)行了,因?yàn)槲疫@里沒有訪問類里的對象,所以可以正常運(yùn)行

第二道:下面程序編譯運(yùn)行結(jié)果是? A、編譯報(bào)錯(cuò) B、運(yùn)行崩潰 C、正常運(yùn)行
class A
{
public:
void PrintA()
{
cout << _a << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->PrintA();
return 0;
}
這里引發(fā)了空指針,因?yàn)槲倚枰蛴∵@里的_a,就要找到那塊空間

也就可以寫成這樣,this指針是空指針,解引用就會(huì)報(bào)錯(cuò)

所以this指針是可以為空的,只要在成員函數(shù)內(nèi)部不訪問其內(nèi)容,程序可以正常執(zhí)行的。
以上就是一文詳解C++中隱含的this指針的詳細(xì)內(nèi)容,更多關(guān)于C++ this指針的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C++使用string的大數(shù)乘法運(yùn)算(3)
這篇文章主要為大家詳細(xì)介紹了C++使用string的大數(shù)乘法運(yùn)算,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-09-09
C++實(shí)現(xiàn)LeetCode(84.直方圖中最大的矩形)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(84.直方圖中最大的矩形),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07
Objective-C的內(nèi)省(Introspection)用法小結(jié)
這篇文章主要介紹了Objective-C的內(nèi)省(Introspection)用法,這是面向?qū)ο笳Z言和環(huán)境的一個(gè)強(qiáng)大特性,需要的朋友可以參考下2014-07-07
C++?select模型簡單聊天室的實(shí)現(xiàn)示例
本文主要介紹了C++?select模型簡單聊天室的實(shí)現(xiàn)示例,使用CMake項(xiàng)目進(jìn)行開發(fā),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05
c++如何實(shí)現(xiàn)跳表(skiplist)
這篇文章主要介紹了c++如何實(shí)現(xiàn)跳表,幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下2020-08-08
VC實(shí)現(xiàn)A進(jìn)程窗口嵌入到B進(jìn)程窗口中顯示的方法
這篇文章主要介紹了VC實(shí)現(xiàn)A進(jìn)程窗口嵌入到B進(jìn)程窗口中顯示的方法,對于理解windows程序運(yùn)行原理的進(jìn)程問題有一定的幫助,需要的朋友可以參考下2014-07-07

