類存儲在內存很簡單 - 幾乎相同的方式的結構。如果您檢查了存儲類實例的地方的內存,您會注意到,它的字段被一個接一個地打包。
儘管如此,如果你的班級有虛擬方法,還是有區別的。在這種情況下,存儲在類實例中的第一件事是指向虛擬方法表的指針,這允許虛擬方法正常工作。你可以在互聯網上閱讀更多關於這個,這是一個更高級的話題。幸運的是,你不必擔心這個問題,編譯器會爲你做所有事情(我的意思是,處理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中。
很好的答案,但指向成員變量的指針呢?變量之間是否也共享變量? – 2013-03-03 13:48:17
我修改了我的答案。現在清楚嗎? – Spook 2013-03-03 15:20:27
是的,非常感謝! – 2013-03-04 12:24:34