2013-03-03 30 views
2

我有個疑問:我可以聲明一個指針指向一個類的成員函數C++對象表示

void (*MyClass::myFunc)(void); 

和我可以聲明一個指針指向一個類的成員變量

int (MyClass::*var); 

我的問題是:在內存(asm級別)中構造的對象(由成員函數和成員變量組成)如何?

我不確定,因爲除了多態性和運行時虛函數,我可以聲明一個指向成員函數的指針,即使沒有對象,這也意味着代碼函數在多個類中共享(儘管它們需要*這個指針正常工作)

但是變量呢?即使沒有對象實例,我怎麼可以聲明一個指向成員變量的指針呢?當然,我需要一個來使用它,但是我可以聲明一個沒有對象的指針這一事實使我認爲內存中的類對象用指向其他內存區域的指針表示它的變量。

我不知道我是否正確解釋了我的懷疑,如果不只是讓我知道,我會盡力解釋它更好

回答

3

類存儲在內存很簡單 - 幾乎相同的方式的結構。如果您檢查了存儲類實例的地方的內存,您會注意到,它的字段被一個接一個地打包。

儘管如此,如果你的班級有虛擬方法,還是有區別的。在這種情況下,存儲在類實例中的第一件事是指向虛擬方法表的指針,這允許虛擬方法正常工作。你可以在互聯網上閱讀更多關於這個,這是一個更高級的話題。幸運的是,你不必擔心這個問題,編譯器會爲你做所有事情(我的意思是,處理VMT,不用擔心)。

讓我們來看看方法。當你看到:

void MyClass::myFunc(int i, int j) { } 

其實編譯器將其轉換成類似:

void myFunc(MyClass * this, int i, int j) { } 

當你罵:

myClassInstance->myFunc(1, 2); 

編譯器生成以下代碼:

myFunc(myClassInstance, 1, 2); 

Ple請記住,這是一種簡化 - 有時比這更復雜一點(特別是當我們討論虛擬方法調用時),但它或多或少地顯示了編譯器如何處理類。如果您使用一些低級別的調試器(如WinDbg),則可以檢查方法調用的參數,並且您會看到,第一個參數通常是您調用該方法的類實例的指針。

現在,所有相同類型的類共享其方法的二進制文件(編譯代碼)。因此,爲每個類實例複製它們沒有意義,所以只有一個拷貝保存在內存中,所有實例都使用它。現在應該清楚,爲什麼即使你沒有類的實例,你也可以獲得指向方法的指針。

但是,如果要調用保存在變量中的方法,則必須提供一個類實例,該實例可以通過隱藏的「this」參數傳遞。


編輯:在迴應評論

您可以在another SO question閱讀更多關於指針成員。我猜,那個指向成員的指針存儲了類實例的開始和指定字段之間的區別。當您嘗試使用指向成員的指針檢索字段的值時,編譯器將定位類實例的開始,並按指向成員的指針字段中存儲的字節數進行移動。

每個類實例都有自己的非靜態字段副本 - 否則它們對我們來說不會有太大用處。

請注意,與指向方法的指針類似,您不能直接使用指向成員的指針,您必須再次提供一個類實例。

我說的話是爲了證明,所以在這裏它是:

class C 
{ 
public: 
    int a; 
    int b; 
}; 

// Disassembly of fragment of code: 

    int C::*pointerToA = &C::a; 
00DB438C mov   dword ptr [pointerToA],0 
    int C::*pointerToB = &C::b; 
00DB4393 mov   dword ptr [pointerToB],4 

你能看到存儲在pointerToA和pointerToB值是多少?字段a與類實例的開頭相距0字節,所以值0存儲在pointerToA中。另一方面,字段b存儲在長度爲4個字節的字段a之後,因此值4存儲在pointerToB中。

+0

很好的答案,但指向成員變量的指針呢?變量之間是否也共享變量? – 2013-03-03 13:48:17

+0

我修改了我的答案。現在清楚嗎? – Spook 2013-03-03 15:20:27

+0

是的,非常感謝! – 2013-03-04 12:24:34