gdb x命令 gdb分析C 物件記憶體布局 二

2021-10-11 08:42:17 字數 2433 閱讀 6484

gdb分析c++物件記憶體布局(一):

多繼承指的是派生類繼承了多個基類。

以下**是有虛函式的類之間實現多繼承。

// multi_hierarchy_test.cpp
對以上**執行g++ -o multi_hierarchy_test multi_hierarchy_test.cpp -g -std=c++11進行編譯。

執行./multi_hierarchy_test後,輸出如下。

(a
生成的派生類d的物件記憶體布局如下,派生類d的生成過程為:首先呼叫基類a的建構函式,此時物件的虛函式表指標指向基類a的虛函式表,接著呼叫基類b的建構函式,行為與基類a一致,最後呼叫派生類d的建構函式,此時,一方面,「覆蓋」基類a和基類b的虛函式表指標,使2個基類的指標都指向派生類d的虛函式表,另外一方面,增加派生類d自己的成員變數到新生成的物件中。

upcast操作時,基類a的指標指向的位址與派生類d的指標指標指向的位址是一樣的,基類b的指標不僅跟派生類d不同,其指向的虛函式表指標指向的是**段non-virtual thunk to d::func_b(),而不是直接指向d::func_b()。

基類a是派生類d的最左基類,而基類b是非最左基類,在多繼承場景下,由上圖可以看出,c++物件的記憶體布局中,乙個派生類可以通過「截斷」的方式完美地轉化為最左基類,但無法完美轉化為非最左基類。這就是upcast時,作為最左基類的基類a與作為非最左基類的基類b表現不同的原因。這個現象可以理解為,派生類與最左基類之間存在「嫡系」繼承關係。

由上圖可知,執行b->func_b()時,首先獲取虛函式表指標_vptr.b(構造過程中原基類b的虛函式表指標),接著獲取其指向的**段non-virtual thunk to d::func_b(),該**段先將this(經過upcast後是基類b型別)轉換為派生類d型別,之後才跳轉到真正的d::func_b()函式。

之所以有型別轉換這個步驟,是因為在多繼承場景下,非最左基類b只是派生類d的乙個部分,所以需要改變身份,變成派生類d,才能真正地呼叫派生類d的d::func_b()函式,而同樣在這個場景下,最左基類a則是派生類d的「嫡系」基類,不需要改變身份,可以理解為就是直接使用單繼承模式下的虛函式機制即可。

除了以上2處不同外,經過upcast後,對基類b型別的指標的操作,就跟操作乙個類b物件是一樣的。這也是c++物件記憶體如此布局的構思藝術所在。

在gdb環境下執行如下命令。

(gdb
根據輸出結果分析如下:

菱形繼承指的是乙個基類分別被兩個派生類繼承,而這兩個派生類又同時被乙個更下一層的派生類所繼承,當生成最下層的這個派生類時,最上層的基類將在最下層的這個派生類中存在兩份。

以下**是有虛函式的類之間實現菱形繼承。

// diamond_hierarchy_test.cpp
以上**中,對基類a執行upcast會發生編譯錯誤,這是因為在派生類d中會存在兩份基類a,編譯器不知道要選擇哪個基類a,存在歧義。

對以上**執行g++ -o diamond_hierarchy_test diamond_hierarchy_test.cpp -g -std=c++11進行編譯。

執行./diamond_hierarchy_test後,輸出如下。

sizeof(a): 16

sizeof(b): 24

sizeof(c): 24

sizeof(d): 56

0x614c20

0x614c20

0x614c38

生成的派生類的物件記憶體布局如下,派生類d的生成過程為:首先呼叫基類b的建構函式,由於基類b是繼承基類a,所以要遞迴往上,呼叫基類a的建構函式,基類b會對基類a發生虛函式表指標的「覆蓋」,接著呼叫基類c的建構函式,同理,也會呼叫基類a的建構函式與基類c對基類a的虛函式表指標的「覆蓋」,至此,基類b與基類c各自具有乙個基類a,最後呼叫派生類d自身的建構函式,同樣地,派生類d對基類b和基類c的虛函式表指標進行「覆蓋」,同時,增加自己的成員變數到新生成的物件中。

同理,基類b作為派生類d的「嫡系」基類,無需經過**段non-virtual thunk to d::func_a()跳轉到 d::func_a(),而非最左基類c則需要。另外,基類c的 c::func_c()並沒有在派生類d中override,所以仍然保留在派生類d的虛函式表中。

在gdb環境下執行如下命令。

(gdb

C 多型原理詳解(GDB除錯分析)

在計算類大小時提及到了類中虛指標及虛函式表的結構,但並沒有相對較為充足的依據,下來借助gdb工具來分析一下c 中虛指標及虛函式表的詳細結構 以下 執行環境均為linux下的64位作業系統 無繼承的單類案例 如下 include using namespace std class a virtual ...

c 物件模型分析

class是一種特殊的struct 在記憶體中class依舊可以看作變數的集合 class與struct遵循相同的記憶體對齊規則 class中的成員函式與成員變數是分開存放的 每個物件有獨立的成員變數 所有物件共享類中的成員函式 執行時的物件退化為結構體的形式 所有成員變數在記憶體中依次排布 成員變...

使用GDB 分析C 類的記憶體分布

首先,如下 1 2 include 3 include 4 5 class cfox 6 13 14 cfox cfox void 15 18 19 void cfox print void 20 23 24 class imyclass 25 31 protected 32 int id 33 c...