C 類空間大小

2021-10-20 22:00:18 字數 4579 閱讀 9581

可以先看下這篇博文:c++虛函式和虛函式表原理,對類內部空間的排布會有了解,對於本文的理解也會很有幫助。

與類大小有關的因素:普通成員變數,虛函式,繼承(單一繼承,多重繼承,重複繼承,虛擬繼承);

與類大小無關的因素:靜態成員變數,靜態成員函式及普通成員函式;

空類即什麼都沒有的類,按上面的說法,照理說大小應該是0,但是,空類的大小為1,因為空類可以例項化,例項化必然在記憶體中占有乙個位置,因此,編譯器為其優化為乙個位元組大小。

某類繼承自空類:

class

base

;class

derived

:public base

此時,derived類的大小為4,derived類的大小是自身int成員變數的大小,至於為什麼沒有加上父類base的大小1是因為空白基優化的問題,在空基類被繼承後,子類會優化掉基類的1位元組的大小,節省了空間大小,提高了執行效率。

首先上兩個類的示例:

class

base1

;class

base2

;

雖然上述兩個類成員變數都是乙個char,乙個int,乙個double,但是不同的宣告順序,會導致不同的記憶體構造模型,對於base1,base2,其成員排列是醬紫的:

base 1類物件的大小為16位元組,而base 2類物件的大小為24位元組,因為不同的宣告順序,居然造成了8位元組的空間差距,因此,我們將來在自己宣告類時,一定要注意到記憶體對齊問題,優化類的物件空間分布。

首先呈上示意類:(64位,指標大小8位元組)

class

base

;class

derived

:public base

;class

derived1

:public base

;

基類base中含有乙個char型成員變數,以及兩個虛函式,此時base類的記憶體布局如下:

記憶體布局的最一開始是vfptr(virtual function ptr)即虛函式表指標(只要含虛函式,一定有虛函式表指標,而且該指標一定位於類記憶體模型最前端),接下來是base類的成員變數,按照在類裡的宣告順序排列,當然啦,還是要像上面一樣注意記憶體對齊原則。

繼承類derived繼承了基類,重寫了base中的虛函式f(),還新增了自己的成員變數,即int型的b,這時,derived的類記憶體模型如下:

此種情況下,最一開始的還是虛函式表指標,只不過,在derived類中被重寫的虛函式f()在對應的虛函式表項的base::f()已經被替換為derived::f(),接下來是基類的成員變數char a,緊接著是繼承類的成員變數int b,按照其基類變數宣告順序與繼承類變數宣告順序進行排列,並注意記憶體對齊問題。

繼承類derived1繼承了基類,重寫了base中的虛函式g(),還新增了自己的成員變數(即double型的b)與自己的虛函式(virtual h() ),這時,derived1的類記憶體模型如下:

此種情況下,derived1類一開始仍然是虛函式表指標,只是在derived1類中被重寫的虛函式g()在對應的虛函式表項的base::g()已經被替換為derived1::g(),新新增的虛函式virtual h()位於虛函式表項的後面,緊跟著基類中最後宣告的虛函式表項後,接下來仍然是基類的成員變數,緊接著是繼承類的成員變數。

首先上示意類:

class

base1

;class

base2

;class

base3

;class

derived

:public base1,

public base2,

public base3

;

首先繼承類多重繼承了三個基類,此外繼承類重寫了三個基類中都有的虛函式virtual f(),還新增了自己特有的虛函式 derived_func(),那麼,新的繼承類記憶體布局究竟是什麼樣子的呢?請看下圖!先來看3個基類的記憶體布局:

緊接著是繼承類derived的記憶體布局:

首先,derived類自己的虛函式表指標與其宣告繼承順序的第乙個基類base1的虛函式表指標合併,此外,若derived類重寫了基類中同名的虛函式,則在三個虛函式表的對應項都應該予以修改,derived中新新增的虛函式位於第乙個虛函式表項後面,derived中新新增的成員變數位於類的最後面,按其宣告順序與記憶體對齊原則進行排列。

首先在講這一節之前,先貼出幾個重要的資訊(乾貨):

;base1與base2本身沒有任何自身新增的資料成員與虛函式,因此,base1與base2都只含有從base繼承來的int a與乙個普通的方法,然後derived又從base1與base2繼承,這時會導致二義性問題及重複繼承下空間浪費的問題:

二義性問題:

derived de;

de.a=10;

//這裡是錯誤的,因為不知道操作的是哪個a

重複繼承下空間浪費:

derived重複繼承了兩次base中的int a,造成了無端的空間浪費

虛擬繼承是怎麼解決上述問題的?

class

base

'class

derived

:virtual

public base

;

derived類記憶體布局如下圖,由於虛擬繼承,derived只會有乙個最初基類的拷貝,該拷貝位於類物件模型的最下面,而想要訪問到基類的元素,需要vbptr指明基類的位置(vbptr作用),假如base中含有虛函式,而繼承類中沒有增添自己的新的虛函式,那麼derived類統一的布局如下:

如果新增了自己的新的虛函式(**如下):

class

base

;class

derived

:virtual

public base

;

那麼derived在vc下繼承類會有自己的虛函式指標,而在gcc下是共用基類的虛函式指標,其分布如下

現在有了上述**的理解我們可以寫出菱形虛擬繼承**及每個類的記憶體布局:

帶實線的框是類確確實實有的,帶虛線是針對base,及base1,base2做了擴充套件後的情況:

base有虛函式,base1還新增了自己新的虛函式,base1也有自己成員變數,base2新增了自己新的虛函式,base2也有自己成員變數,則上圖全部虛線中的部分都將存在於物件記憶體布局中。

原文:c++類大小詳盡講解

allocation類(空間配置類)

c 提供了new和delete來管理動態記憶體空間 new有兩個操作 在堆區申請記憶體空間,在分配的記憶體空間構造物件 delete兩個操作 呼叫析構函式銷毀物件,記憶體 例 string p new string 10 構造了10個空類 而有的時候我們不會把這些空間都使用完,這樣就產生了額外的物件...

C 空類,空虛基類處理及類大小

對於乙個空類,編譯器會加入1byte的大小,使得這乙個類的兩個物件在記憶體中有獨一無二的位址。如下 class x class y public virtual x class z public virtual x class a public y,public z 每個類的大小 傳統編譯器對emp...

jboss中不同war包間共享類空間

jboss中不同應用之間如何共享類和資源 通常如果希望在jboss不同應用之間共享類和資源,我們應將類和資源放在jboss server default lib 下面,這樣所有的應用可以共享資源 jboss中如果類和和資源放在不同的war包中,卻想在不同的應用間何共享war包中web inf cla...