標籤:

C++中this指針藏在哪裡?

this指針應該是指向對象的,那麼這個指針不是應該存在對象中的嗎?

#include &
struct A {
int i;
int j;
};
int main()
{
A a;
std::cout &<&< sizeof(a); }

最後輸出的結果是8.這就說明了this指針不存在於對象中?那麼它到底藏在哪裡呢?


題主的意思很明白,他認為this最好也存在結構體中,這樣,用的時候就可以找到自己的結構體中的this來使用了。

而實際上,如何找到「自己」呢?還是通過this。於是我們得到了:this-&>this

繼續分析,無限循環

---------------------------------------------------------------------------------------------------------

this是編譯器看的,他是「當前對象」的意思。如果運行期間需要訪問對象,此時的this指向的就是這個對象,編譯器將其替換為當前對象的地址就ok了。簡單來說就是這樣啦。


那你認為 char* p 應該能藏在 char 里?


簡單來說吧,你在哪裡能用到this-&>xxxx?只有在類的成員函數里。而調用這個函數的時候其實已經悄悄傳入了this參數,也就是說this這個東西其實根本不是對象的一個成員,而是函數的一個參數。

你得跳出面向對象的思想去看這個問題,因為C++編譯到彙編,不存在對象這種東西,只有函數和各種地址、數據。一個類有100個對象(實例),但函數只有一份,所以實際上不是對象擁有了一個函數,而是函數被告知操作一個對象。

A a();

此時a在棧上,棧上的元素,地址是編譯器知道就行了的,可能存在寄存器里,也可能只存在幾條指令里。

A* a = new A();

此時這個對象在堆里,a存著它的地址,在棧上,同時這個a的值等同於a這個對象的「this」的值。


題目里將「指針」和「指針變數」弄混了,所以才會有這樣的疑問。

「指針」只是類型的名字:變數可以是指針類型的,表達式也可以是指針類型的。「this 指針」不等價於「this 指針變數」,事實上也正是如此:this 是關鍵詞、是表達式,但偏偏就不是變數

(這就類似 if 藏在哪裡?sizeof 藏在哪裡?3 藏在哪裡?……)


題主的意思是類體內方法用 this 指針來找自己,但是 this 沒有定義是吧。

實際上你調用 foo-&>bar(x); 的時候,編譯器就已經把 foo 指針作為第一個參數壓棧了,這第一個參數就是 this。

你用函數指針調用成員函數的時候把對象當作第一個參數,效果和直接調用成員函數是一樣的:


你可以不那麼嚴格地認為:

class MyClass
{
void my_call(int arg1, float arg2) {}
};

大致上相當於:

struct MyClass
{
};

void MyClass_my_call(MyClass* this, int arg1, float arg2);

實際上,C語言編製的庫,很多都是這樣的。

當然,實際上method call並不完全是這樣實現的,比如this參數會被特別對待。不過這種細節問題對你暫時不重要。

另外,sizeof是一個編譯時的行為:編譯器顯然知道一個類型的尺寸,並就地把它替換為字面值。程序在運行的時候根本沒有sizeof這個東西。你在這裡寫sizeof(this)和直接寫8是一樣的,只不過sizeof會給你額外的好處:你不用手工計算它的尺寸,編譯器自動給你算,省得你算錯,比如32位平台上,sizeof(this)就不是8,而通常是4。


不考慮有時的編譯器優化的話,IA-32 下,微軟 C++ 編譯器會放在 ECX 寄存器里,GCC 會把 this 指針作為第一個推入棧中的參數。


我來給你舉個例子,你就明白了。

假如有這樣一個C++代碼:

class SomeClass {
private:
int count;
public:
SomeClass() {
this-&>count = 0;
}
void inc() {
this-&>count ++;
}
void add(int x) {
this-&> count += x;
}
};

int main() {
SomeClass a;
a.inc();
a.add(5);
return 0;
}

在C++編譯器對上述代碼進行編譯的時候,會被變換成和下面的代碼等價的形式:

struct SomeClass {
int count;
}

// 構造函數
void SomeClass_SomeClass(SomeClass* _this) {
_this-&>count = 0;
}

void SomeClass_inc(SomeClass* _this) {
_this-&>count ++;
}

void SomeClass_add(SomeClass* _this, int x) {
_this-&> count += x;
}

int main() {
SomeClass a;
SomeClass_SomeClass(a); // 調用構造函數
SomeClass_inc(a);
SomeClass_add(a, 5);
return 0;
}

只要編譯器在每一個調用成員函數的地方做一次變換,把當前的對象作為參數傳到成員函數里去,就能給你一種在使用this指代當前對象的感覺。

如果實在好奇這個過程到底發生了什麼,可以將你寫的C++程序反彙編後,看編譯出來的程序到底在幹些什麼,就能夠明白地清清楚楚了。(當然,要先熟悉彙編)

還有,僅僅通過sizeof來判斷是不靠譜的。比如:

struct hahaha{
int x;
char y;
int z;
char zz;
}

sizeof(struct hahaha)是多少?


一般而言,是編譯器推斷出來的。但是在那個對象內部是沒有的。


並不需要存,因為this的地址是編譯期決定的,裡面對成員的訪問都是相對地址。


題主去看看《深入探索c++模型》。

類的函數有一個隱藏的參數是this指針,每次調用的時候會傳入的。

C++的設計準則之一就是:

nonstatic member function 至少必須和一般的nonmember function有相同的效率。

nonstatic member function會轉換為nonmember形式。主要會做以下幾個工作:

1.改寫函數原型,安插一個額外的參數,也就是this指針。

2.將每一個對「nonstatic data member的存取操作」改為經由this指針來存取。

3.將member function重寫成一個外部函數,對函數名稱進行「mangling」處理,使它在程序中成為一個獨一無二的辭彙。

void Point3d::translate()
{
x = 1;
y = 2;
z = 3;
}

轉化,省略了函數名稱處理的處理,用Point3d::替代。

void Point3d::translate(Point3d *const this)
{
this-&>x = 1;
this-&>y = 2;
this-&>z = 3;
}


並沒有「隱藏這一說」

所有成員函數,編譯器都會幫你改成自由函數,其中一個參數就是 this


你這樣理解:

A* a = xxx;

a-&>Call();等價於A::Call(a) 即函數這樣聲明static ReturnType A::Call(A* this)

把this當做第一個參數傳到函數里


this 是指代對象地址,在對象中並不存在。


對於MS編譯器,this指針放在ecx寄存器中


可以這麼理解:this指針是用在member function里的,自然只是一個函數參數,編譯器自己給你插進去,不算對象本身的數據成員。


周末看到這個問題,心裡第一反應是ecx寄存器,但看已有答主回答。並且我用著手機,感覺打字不方便,也不想再深入地回答。

然後今天上班時看看訂閱的rss中,剛好發現伯樂在線有一篇文章(也是轉的)是詳細說this指針的,比我之前能想到的詳細多了,特此轉來以供大家 參考。

C++ 中 this 指針的用法詳解 - 文章 - 伯樂在線


this是給編譯器看的,兄弟


答主。面向對象編程在編譯過後並不存在所謂對象這個東西。對象的概念只存在在高層次的抽象中。

所謂對象方法,實際上只是個普通的函數,只不過在你寫代碼的時候,這個函數是歸屬於某個對象或者某個類的,而編譯成程序後,這個方法和普通的函數沒有區別。實際上,在方法中使用this的原理非常簡單,就是在傳參時把對象所在的內存地址傳進去。就像在python中類方法生命時需要有self變數。


this是內存中某個class開始的內存地址,變數是這個內存地址加上它的偏移值 像int a是佔四個位元組,也就是this 加上四個位元組就可以訪問到a的值


推薦閱讀:

一個類有幾個this指針?如果只有一個,那是怎麼區分不同的對象呢?
C++中的struct?
如何快速入門UE4開發?
關於 《C++ Primer 5th》,使用了「 =default 」的默認構造函數相關問題?
內存池除了減少內存申請和釋放的開銷之外還有什麼提升性能或者方便之處?

TAG:C |