本文通過觀察編譯器生成的匯編代碼,分析普通成員函數、靜態成員函數以及指針調用成員函數的底層實現,為後續探討虛函數、虛繼承奠定基礎。
C010 obj;
PRINT_OBJ_ADR(obj)
obj.foo(); // 對象調用普通成員函數
C012::sfoo(); // 靜態成員函數調用
C010 * pt = &obj;
pt->foo(); // 指針調用普通成員函數
匯編:
00422E09 lea ecx,[ebp+FFFFF967h] ; 載入對象地址到 ecx (this指針)
00422E0F call 0041E289 ; 直接調用固定地址 (靜態綁定)
進入函數體:
01 push ebp
02 mov ebp,esp
...
07 push ecx ; 保存 this 指針
...
12 pop ecx ; 彈出 this 到 ecx
13 mov dword ptr [ebp-8],ecx ; 存入局部變量 (this)
14 mov eax,dword ptr [ebp-8]
15 mov byte ptr [eax],2 ; 通過 this 修改成員變量 (偏移 0)
關鍵點:VC7.1 使用 ecx 傳遞 this 指針(而非棧傳遞),函數入口將 ecx 保存至棧帧局部變量區,後續通過該局部變量訪問成員。
00422E14 call 0041DD84
極其簡單:無 this 指針處理,直接調用固定地址。
00422E25 mov ecx,dword ptr [ebp+FFFFF958h] ; 解引用指針獲取對象地址
00422E2B call 0041E289 ; 同樣直接調用
與對象調用幾乎相同,差別在於獲取 this 的方式:對象直接取地址,指針需先解引用。
this 指針通過 ecx 寄存器傳遞(Microsoft x86 calling convention)。this,調用開銷最小。