<接上篇>
我們接著來看一段C++的代碼:
class A
{
public:int func(int j){return j +_i;}
private:int _i;
};int main()
{A a;a.func(3);return 0;
}
這里定義了一個類A,在main函數中定義了A類的對像a。同時用a調用了成員函數func。我們來看一下main函數的匯編代碼:
pushq %rbpmovq %rsp, %rbpsubq $16, %rsp //rsp = rsp - 16leaq -4(%rbp), %rax //rax = rpb -4movl $3, %esi //esi = 3movq %rax, %rdi //rdi = raxcall A::func(int)movl $0, %eaxleaveret
在調用A::func之前,賦值了兩個寄存器:rdi和rsi. 由上篇文單可知,這兩個寄存器用于函數調用時,傳遞第1和第2個參數。那么這里我們有疑問:A::func(int)明明只有一個參數,為什么調用時,傳遞了兩個參數呢?另一個參數是什么呢?答案就是:在調用成員函數時,this指針會做為一個隱含的參數傳遞給成員函數,并且是作為第一個參數。那么this指針又代表什么呢,this指針就是指向類對象的一個地址。對應上面匯編代碼即是rbp-4。源代碼a.func(3)相當于func(this, 3)也就是func(&a, 3);?
為了方便理解,我畫出了main函數的棧空間,如下所示:
this指針存儲的是a對象的地址。即rbp-4. 此時a對象里面只有一個int型的成員變量i, 占用4個字節。
接下來,我們分析一下func函數,匯編如下:
A::func(int):pushq %rbpmovq %rsp, %rbpmovq %rdi, -8(%rbp) //*(rbp-8) = rdimovl %esi, -12(%rbp) // *(rbp-12) = esimovq -8(%rbp), %rax // rax = *(rbp-8) movl (%rax), %edx // edx = *raxmovl -12(%rbp), %eax // eax = *(rbp-12)addl %edx, %eax // eax += edxpopq %rbpret
func函數棧空間如下:??
??
func中會先分配棧空間rbp-8, rbp-12來存儲傳遞過來的參數rdi(this)以及esi(3)。 然后根據這些參數來做下一步處理。
總結:
1)this指針的本質即對象的地址。
2)在調用類成員函數時,C++編譯器會將其作為函數的第一個參數,傳遞給成員函數。