2011-07-23 39 views
3

我正在使用Eckel的「Thinking in C++」學習C++。它聲明如下:Visual C++編譯器如何將此ptr傳遞給被調用的函數?

  • 如果一個類包含虛擬方法,則爲該類創建一個虛擬函數表等。函數表的工作原理將被粗略地解釋。 (我知道一個vtable不是強制性的,但Visual C++創建了一個。)
  • 調用對象作爲參數傳遞給被調用的函數。 (這可能不適用於Visual C++(或任何編譯器))。我試圖找出VC++如何將調用對象傳遞給該函數。

要在Visual C測試兩個點++,我創建了下面的類(使用Visual Studio 2010,WinXP的家庭32位):

ByteExaminer.h:

#pragma once 
class ByteExaminer 
{ 
public: 
short b[2]; 
    ByteExaminer(void); 
    virtual void f() const; 
    virtual void g() const; 
    void bruteFG(); 
}; 

ByteExaminer.cpp :

#include "StdAfx.h" 
#include "ByteExaminer.h" 

using namespace std; 

ByteExaminer::ByteExaminer(void) 
{ 
    b[0] = 25; 
    b[1] = 26; 
} 

void ByteExaminer::f(void) const 
{ 
    cout << "virtual f(); b[0]: " << hex << b[0] << endl; 
} 

void ByteExaminer::g(void) const 
{ 
    cout << "virtual g(); b[1]: " << hex << b[1] << endl; 
} 

void ByteExaminer::bruteFG(void) 
{ 
    int *mem = reinterpret_cast<int*>(this); 
    void (*fg[])(ByteExaminer*) = { (void (*)(ByteExaminer*))(*((int *)*mem)), (void (*)(ByteExaminer*))(*((int *)(*mem + 4))) }; 
    fg[0](this); 
    fg[1](this); 
} 

通過虛表中bruteFG()作品導航 - 當我打電話fg[0](this),調用。但是,不起作用的是將this傳遞給該函數 - 意味着this->b[0]未正確打印(垃圾出來,實際上我很幸運,這不會產生段錯誤)。

所以對於

ByteExaminer be; 
be.bruteFG(); 

實際產量:

virtual f(); b[0]: 1307 
virtual g(); b[1]: 0 

所以我應該怎麼着手得到正確的結果? this指針如何傳遞給VC++中的函數? (Nota bene:我不會嚴肅地編程這種方式,這是「爲了lulz」或學習經驗,所以不要試圖將我轉換爲適當的C++ ianity: ))

+0

你只是好奇它是如何工作的(DeadMG的答案應該滿足你的需求),還是你在尋找類似於指向成員操作符(它是C++語言的一部分)或'代表'的東西有幾種實現(因爲指向成員的操作符有限制),包括在Boost或TR1中? –

回答

4

Visual Studio中的成員函數有一個特殊的調用約定__thiscall,其中this被傳入一個特殊的寄存器中。哪一個,我不記得,但MSDN會說。如果你想調用一個vtable中的函數指針,你必須下到彙編程序。

當然,你的代碼展品大量不確定behaviour-它只是確定別名使用charunsigned char指針的對象,絕對不是int指針 - 甚至忽略了整個虛函數表的假設的事情。

+0

在x86和x64上,'ecx'。 –

+0

哦。感謝提示 - 谷歌搜索__thiscall實際上是足夠的。 'this'總是在ecx中傳遞(在x86上也是)。請參閱http://msdn.microsoft.com/en-us/library/ek8tkfbw%28v=vs.80%29.aspx – Hinton

0

OK使用DeadMG的提示,我發現不使用匯編的方式:

1)拆下ByteExaminer *從FG []數組 2)功能ARG功能void callfunc(void (*)());添加到ByteExaminer:

void ByteExaminer::callfunc(void (*func)()) 
{ 
    func(); 
} 

...這顯然工作,因爲func()是在callfunc中使用的第一件事,所以ecx顯然以前沒有改變。但這是一個骯髒的伎倆(正如你在上面的代碼中看到的,我總是在尋找乾淨的代碼)。我仍然在尋找更好的方法。

+1

這應該是對問題的編輯。 – Puppy

+0

我最近收到通知,答案不應該包含在原始問題中。 – Hinton

相關問題