C 物件模型

2021-07-04 09:23:37 字數 2107 閱讀 8561

如下面的base類定義:

其物件在記憶體中的分配如下:

在此模型中,non static資料成員被放置到物件內部,static資料成員(放置到全域性資料區),static函式成員(放置到全域性資料區),non static函式成員(放置到**段)均被放到物件之外。對於虛函式的支援則分兩步完成:

每乙個class產生一堆指向虛函式的指標,放在**中。這個**稱為虛函式表(virtual table,vtbl)。

每乙個物件被新增乙個指標,指向相關的虛函式表vtbl。稱這個指標為vptr。vptr的設定和重置都由每乙個class的建構函式、析構函式和拷貝賦值運算子自動完成。

另外,虛函式表的位址前面設定了乙個指向type_info的指標,rtti執行時型別識別,由編譯器在編譯時生成特殊型別的資訊,包括物件繼承關係,物件本身描述,rtti是為多型而生成的資訊,所以只有具有虛函式的物件才會生成。

這個模型的優點在於它的空間和訪問時間的效率;缺點是如果應用程式本身未改變,但當其非靜態的成員函式新增、刪除或修改時,需要重新編譯。

無重寫,即派生類中沒有與基類同名的虛函式。有如下派生類:

base、derived的類圖如下所示:

base的模型跟上面一樣,不受繼承的影響。derived不是虛繼承,所以是擴充已存在的虛函式表,所以結構如下所示:

派生類中重寫了基類的print()函式。

base、derived_overwrite的類圖如下所示:

重寫print()函式在虛函式表中如下:

從單繼承可以知道,派生類中只是擴充了基類的虛函式表。如果是多繼承的話,又是如何擴充的呢?

每個基類都有自己的虛表;

子類中的成員函式被放到了第乙個基類的表中;

記憶體布局中,其父類布局依次按宣告順序排列;

每個基類的虛表中的print()函式都被overwrite成了子類的print()。這樣做就是為了解決不同的基類型別的指標指向同乙個子類的例項,而能夠呼叫到實際的函式。

上面的三個類中,

derived_mutlip_inherit

繼承自base、base_1

兩個類,

derived_mutlip_inherit

的結構如下所示:

虛繼承是為了解決重複繼承中多個間接父類造成的二義性問題,所以不能簡單的擴充每個基類的虛函式表,這樣會造成基類有多個虛函式表。

虛繼承的派生類的記憶體結構,和普通繼承完全不同。虛繼承的子類,有單獨的虛函式表,另外也單獨儲存乙份父類的虛函式表,兩部分用0x00000000來做分界。派生類的記憶體中,首先是自己的虛函式表,然後是自己的資料成員,然後是0x00000000,然後就是基類的虛函式表和基類的資料成員。

如果派生類沒有自己的虛函式,就不會有自己的虛函式表,但是派生類的資料成員和基類之間,仍然需要0x00000000來間隔。

因此,在虛繼承中,派生類和基類的資料,是完全間隔的,先存放派生類自己的虛函式表和資料,中間以0x00000000間隔,最後儲存基類的虛函式表和資料。如果派生類複寫了基類的虛函式,則將派生類記憶體中基類的虛函式表的相應函式替換。

簡單虛繼承的兩個類base、

derived_virtual_inherit1的關係如下所示:

derived_virtual_inherit1

的物件模型如下圖:

菱形繼承關係如下圖:

derived_virtual

的物件模型如下圖:

【原創位址】:

c 物件模型

很久之前就想總結一下c 的記憶體使用機制。直到現在剛考完試之制,去實習之前,才有時間完成這事。1.程式使用記憶體區 乙個程式占用的記憶體區一般分為5種 1 全域性 靜態資料區 儲存全域性變數及靜態變數 包括全域性靜態變數和區域性靜態變數 2 常量資料區 儲存程式中的常量字串等。3 區 儲存程式的 4...

C 物件模型

很久之前就想總結一下c 的記憶體使用機制。直到現在剛考完試之制,去實習之前,才有時間完成這事。1.程式使用記憶體區 乙個程式占用的記憶體區一般分為5種 1 全域性 靜態資料區 儲存全域性變數及靜態變數 包括全域性靜態變數和區域性靜態變數 2 常量資料區 儲存程式中的常量字串等。3 區 儲存程式的 4...

C 物件模型

簡單物件模型 乙個c 物件儲存了所有指向成員的指標,而成員本身不儲存在物件中。也就是說不論資料成員還是成員函式,也不論這個是普通成員函式還是虛函式,它們都儲存在物件本身之外,同時物件儲存指向它們的指標。示意圖如右。簡單物件模型對於編譯器來說雖然極盡簡單,但同時付出的代價是空間和執行期的效率.顯而易見...