這裡就先從以下幾個點進行說明吧:
虛繼承:在繼承定義中包含了virtual關鍵字的繼承關系;
虛基類:在虛繼承體系中的通過virtual繼承而來的基類,需要注意的是:class CSubClass : public
virtual CBase {};
其中CBase稱之為CSubClass的虛基類,而不是說CBase就是個虛基類,因為CBase還可以不不是虛繼承體系中的基類。
微軟的VS2010提供了一個新的選項,給用戶顯示C++對象在內存中的布局。這個選項就是:
[cpp] view plaincopyprint?具體使用方法如下,在寫好相應的cpp文件之後,需要啟動VS2010的命令行工具“Visual Studio 2010Command Prompt”,切換到cpp文件所在目錄之後,輸入如下的命令:
cl當然就是MS的編譯器;[filename].cpp就是你所想要查看的class所在的cpp文件(class定義在頭文件也沒關系,還是只要編譯cpp文件即可);而你需要在最後加上[className],也就是你需要查看的class的類名。
【舉例】test.cpp文件代碼如下:
[cpp] view plaincopyprint?查看Derived這個類的對象在內存中的布局,那麼就可以用下面的命令行:
結果顯示如下:
可以看到class
Derived的對象的內存布局,在派生類對象的開始包含了基類Base的對象,其中有一個虛表指針,指向的就是下面的
Derived::$vftable@ (virtual function table),表中包含了Derived類中所有的虛函數。
在這一小節裡面我主要從他面試的幾個題目中來談談虛繼承的內存模型。
[cpp] view plaincopyprint?
輸出結果是:
在命令行中輸入:
[cpp] view plaincopyprint?從這個內存布局就可以看出來class A、class A1和ClassB的大小,本身class A的大小應該是1bytes的內存定位大小加上虛函數指針4bytes因為有了虛函數指針後1bytes的占 位就可以取消了。所以A的大小就是4bytes,同理Class A1。對於Class B它主要是從class A和class A1(虛繼承)而來,所以B裡面包含有一個A和A1同時因為是虛繼承所以就有一個指向虛基類(A1)的vbptr指針。這裡為了方便我做個圖直觀一點:
所以說class B的大小是12bytes
[cpp] view plaincopyprint?
上面代碼二輸出的結果:
class E的大小是不是有點怪,在命令行中輸入:
[cpp] view plaincopyprint?如前面黑色字體標注一樣,因為classE是多重虛繼承,所以在內存中的布局是分為固定局部和共享局部,固定局部的大小就int a,b 所以是8 bytes。我的上一篇博文(VC++對象布局的奧秘:虛函數、多繼承、虛擬繼承)對這個內存某型有個大概的講解,在這就不多言了。
[cpp] view plaincopyprint?這個地方的4表示E的vbtable與虛基類A首地址的偏移量,同理,8,12,16這個就不用我說了。既然這都給出了vbtable域虛基類的地址偏移量了,說明在E對象的內存中還是存在分配的空間。
從vs2010的內存來看的確也是分配了,通過前面的vbtable的偏移來看對象的大小就是16bytes(a是class A的首地址,b是classB的首地址)。有人會問為什麼不是20bytes?上面的內存分配偏移是16就說明有20bytes。偏移16,剛好在變量b 的下面分配4bytes的C(這說的不准確,不過好明白)這樣偏移是16的地方就是D,vbtable現在可以正常定位,Class D為空,就沒有必要再分配4bytes的空間,所以sizeof E的大小應該是:vbtable指針(4bytes) +固定局部(a,b工8bytes)+ C 的4bytes(這有點不好明白,不過下面我還有例子,加深理解)。
[cpp] view plaincopyprint?
上面代碼二輸出的結果:
這回感覺還是很奇怪吧,看看內存布局吧。
首先,看看vbtable把,是不是很奇怪,為什麼A,B的偏移都是4,ClassA本身就是空,剛好ClassB有一個成員所以肯定需要給classB 分配內存的,所以這樣就可以找到A的偏移,Class C和Class D就沒辦法了沒辦法計算偏移,所以就給ClassC分配了內存,ClassC有了內存這樣D就可以的偏移也就出來了,這時候就有人問為什麼ClassD的 偏移為什麼不是8呢(說實話我也沒搞懂,我的猜想是對象本身為空,但是為了內存對齊所以就是4bytes。希望懂的大神給以指點,我通過調試多個例子,得 出來的,下面的例子就就更好的說明了這點),
[cpp] view plaincopyprint?
輸出結果是:
再看看內存模型吧
從vbtable來看,裡面存儲的偏移class E的大小默認固定布局是4bytes,共享布局裡面classA、class B和classC的大小是12bytes。所以就是16bytes。
來源:http://blog.csdn.net/wangqiulin123456/article/details/8059536