c 好玩的東西

2021-07-31 01:23:04 字數 2970 閱讀 4991

class 的大小

乙個空 class 的大小為 1 位元組,因為編譯器需要安插進去乙個 char,使得這個 class 物件得以在記憶體中被配置獨一無二的位址。雖然空 class 大小為 1 位元組,但是假如某個類 a 繼承該空 class,計算類 a 的大小時會優化父類空 class 的大小,如類 a 為空,sizeof(a) = 1,不空,則為類a真實資料大小。

我們通常說某個 class 內部有 virtual function 儘管沒有資料成員,它的大小仍為為 4 位元組,因為它有乙個 vptr,指向乙個 vtbl ,所以按指標算大小就是 4 位元組。實際上,就算沒有 virtual function,如果某個類虛繼承別的類,編譯器仍生成有 vtbl ,因為它的 vtbl 還要用來儲存 virtual base class object(虛基類子物件)的 offset 。

對於 virtual 繼承,所有的 virtual base class subobject 在派生類中只保留乙份,所以計算派生類物件時,按乙份計算即可。

計算 class 的大小時,還要考慮記憶體對齊,標準就是乙個 bus 的長度,32 位為 4 位元組。不過要注意,派生類資料成員並不會填補基類花在記憶體對齊上的部分。

下面舉出無數例子來驗證結論 :)

case 1 :class a 為空時的普通繼承、普通繼承有成員、虛繼承、有虛函式

class a ;  

class b : public a ;

class c : public a ;

class x : virtual

public a ;

class y ;

std::cout

g++編譯器生成的c++類例項,虛函式與虛基類位址偏移值共用乙個虛表(vtable)。類例項的開始處即為指向所屬類的虛指標(vptr)。實際上,乙個類與它的若干祖先類(父類、祖父類、…)組成部分共用乙個虛表,但各自使用的虛表部分依次相接、不相重疊。

g++編譯下,乙個類例項的虛指標指向該類虛表中的第乙個虛函式的位址。如果該類沒有虛函式(或者虛函式都寫入了祖先類的虛表,覆蓋了祖先類的對應虛函式),因而該類自身虛表中沒有虛函式需要填入,但該類有虛繼承的祖先類,則仍然必須要訪問虛表中的虛基類位址偏移值。這種情況下,該類仍然需要有虛表,該類例項的虛指標指向類虛表中乙個值為0的條目。

該類其它的虛函式的位址依次填在虛表中第乙個虛函式條目之後(記憶體位址自低向高方向)。虛表中第乙個虛函式條目之前(記憶體位址自高向低方向),依次填入了typeinfo(用於rtti)、虛指標到整個物件開始處的偏移值、虛基類位址偏移值。因此,如果乙個類虛繼承了兩個類,那麼對於32位程式,虛繼承的左父類位址偏移值位於vptr-0x0c,虛繼承的右父類位址偏移值位於vptr-0x10.

乙個類的祖先類有複雜的虛繼承關係,則該類的各個虛基類偏移值在虛表中的儲存順序尊重自該類到祖先的深度優先遍歷次序。

microsoft visual c++與虛繼承

microsoft visual c++與g++不同,把類的虛函式與虛基類位址偏移值分別放入了兩個虛表中,前者稱為虛函式表vftbl,後者稱虛基類表vbtbl。因此乙個類例項可能有兩個虛指標分別指向類的虛函式表與虛基類表,這兩個虛指標分別稱為虛函式表指標vftbl與虛基類表指標vbtbl。當然,類例項也可以只有乙個虛指標,或者沒有虛指標。虛指標總是放在類例項的資料成員之前,且虛函式表指標總是在虛基類表指標之前。因而,對於某個類例項來說,如果它有虛基類指標,那麼虛基類指標可能在類例項的0位元組偏移處,也可能在類例項的4位元組偏移處(對於32位程式來說),這給類成員函式指標的實現帶來了很**煩。

乙個類的虛基類指標指向的虛基類表的首個條目,該條目的值是虛基類指標到整個類例項記憶體首位址的偏移值。即obj.vbtbl - &obj。虛基類第2、第3、… 個條目依次為該類的最左虛繼承父類、次左虛繼承父類、…的記憶體位址相對於虛基類表指標自身位址(即 &vbtbl)的偏移值。

如果乙個類同時有虛繼承的父類與祖父類,則虛祖父類放在虛父類前面。

case 2:class a 含有乙個 char 時,還是上述種類:

#include 

using

namespace

std;

class a ;

class b : public a ;

class c : public a ;

class c_ : public a ; // c_

class x : virtual

public a ;

int main()

對齊就行了。

case 3:特殊一點的

#include 

using

namespace

std;

class a ;

class b : virtual

public a ;

int main()

輸出結果分析:8 這個結果或許有點驚訝,並沒有直接 char + char = 2,然後再對齊至 4 位元組。因為實際上這是錯誤的。

派生類不會填補基類花在記憶體對齊上的無用空間!

看一下《深度探索c++物件模型》原話,其中 concrete1 為基類,concreae2 為派生類 :

也就是說發生 concrete1 subobject 的複製操作時,就會破壞 concrete2 members。即基類子物件複製到派生類,會覆蓋掉派生類後來增加的成員。

case 4:(重點)關於虛基類有2個例子,這是第乙個:

[cpp] view plain copy

print?

class a ;

class b : virtual public a ;

class c : virtual public a ;

class x : public b, public c ;

std::cout<

ubuntu 安裝 pygame 很好玩的東西

1.簡介 sudo apt get install python pygame 其餘原始碼和其他平台的安裝包如rpm可以訪問 找到。如果python沒有安裝開發庫,也會導致pygame不能安裝,比如找不到python.h 等檔案 sudo apt get install python2.6 dev ...

ubuntu 安裝 pygame 很好玩的東西

1.簡介 sudo apt get install python pygame 其餘原始碼和其他平台的安裝包如rpm可以訪問 找到。如果python沒有安裝開發庫,也會導致pygame不能安裝,比如找不到python.h 等檔案 sudo apt get install python2.6 dev ...

C 幾個好玩的小例子

這個感覺挺好的,輸入乙個年份,就能幫助你判斷是不是潤年,console.writeline 請輸入年份 string stryear console.readline 接收使用者輸入的內容 int year convert.toint32 stryear 將內容轉換為int型別的數字 bool re...