簡體   English   中英

有關C ++中多重繼承,虛擬基類和對象大小的問題

[英]Question on multiple inheritance, virtual base classes, and object size in C++

以下代碼打印20,即sizeof(z)為20。

#include <iostream.h>
class Base
{
      public:
            int a;
};

class X:virtual public Base
{
      public:
            int x;
};

class Y:virtual public Base
{
      public:
            int y;
};

class Z:public X,public Y
{
};

int main()
{
Z z;
cout << sizeof(z) <<endl;
}

如果我不在這里使用虛擬基類,即對於以下代碼:sizeof(z)是16。

#include <iostream.h>
class Base
{
      public:
            int a;
};

class X:public Base
{
      public:
            int x;
};

class Y:public Base
{
      public:
            int y;
};

class Z:public X,public Y
{
};

int main()
{
Z z;
cout << sizeof(z) <<endl;
}

為什么sizeof(z)在第一種情況下更多(20)? 不應該是12,因為Base只會在Z中包含一次嗎?

讓我們看看這兩種情況的類布局。

如果沒有虛擬,你有兩個基類(“X”和“Y”),每個類都有一個整數,每個類都集成了一個“Base”基類,它也有一個整數。 這是4個整數,每個32位,總共16個字節。

Offset  Size  Type  Scope  Name
     0     4   int   Base     a
     4     4   int      X     x
     8     4   int   Base     a
    12     4   int      Y     y
    16 size (Z members would come at the end)

(編輯:我已經在DJGPP中編寫了一個程序來獲取布局並調整表格來解釋它。)

現在讓我們談談虛擬基類:它們用指向共享實例的指針替換類的實際實例。 你的“Z”類只有一個“Base”類,“X”和“Y”的兩個實例都指向它。 因此,你有X,Y和Z中的整數,但你只有一個Z.這意味着你有三個整數,或12個字節。 但是X和Y也有一個指向共享Z的指針(否則他們不知道在哪里找到它)。 在32位機器上,兩個指針將增​​加8個字節。 這總計你看到的20。 內存布局可能看起來像這樣(我還沒有驗證它...... ARM有一個例子,其中排序是X,Y,Z,然后是Base):

Offset  Size        Type  Scope  Name  Value (sort of)
     0     4 Base offset      X     ?  16 (or ptr to vtable)
     4     4         int      X     x
     8     4 Base offset      Y     ?  16 (or ptr to vtable)
    12     4         int      Y     y
    16     4         int   Base     a
    20 size (Z members would come before the Base)

因此,內存差異是兩件事的組合:一個較少的整數和兩個以上的指針。 與另一個答案相反,我不相信vtables支付任何(編輯)直接(/編輯)卷,因為沒有虛函數。

編輯:ppinsider提供了有關gcc案例的更多信息,其中他演示了gcc通過使用其他空的vtable(即沒有虛函數)來實現指向虛基類的指針。 這樣,如果有虛函數,則在類實例中不需要額外的指針,需要更多內存。 我懷疑缺點是進入基類的額外間接。

我們可能希望所有編譯器都這樣做,但也許不會。 ARM頁面225討論虛擬基類而不提及vtable。 第235頁專門針對“具有虛函數的虛擬基類”,並且有一個圖表,指示存儲器布局,其中有來自X和Y部分的指針,這些指針與指向vtable的指針是分開的。 我建議任何人不要理所當然地認為Base的指針將以表的形式實現。

馬克桑特森的回答幾乎都是錢,但斷言沒有vtables是不正確的。 您可以使用g ++ -fdump-class-hierarchy來顯示正在發生的事情。 這是no virtuals案例:

Class Base
   size=4 align=4
   base size=4 base align=4
Base (0x19a8400) 0

Class X
   size=8 align=4
   base size=8 base align=4
X (0x19a8440) 0
  Base (0x19a8480) 0

Class Y
   size=8 align=4
   base size=8 base align=4
Y (0x19a84c0) 0
  Base (0x19a8500) 0

Class Z
   size=16 align=4
   base size=16 base align=4
Z (0x19b1800) 0
  X (0x19a8540) 0
    Base (0x19a8580) 0
  Y (0x19a85c0) 8
    Base (0x19a8600) 8

要特別注意“基本大小”參數。 現在是虛擬案例,只顯示Z:

Class Z
   size=20 align=4
   base size=16 base align=4
Z (0x19b3000) 0
    vptridx=0u vptr=((& Z::_ZTV1Z) + 12u)
  X (0x19a8840) 0
      primary-for Z (0x19b3000)
      subvttidx=4u
    Base (0x19a8880) 16 virtual
        vbaseoffset=-0x0000000000000000c
  Y (0x19a88c0) 8
      subvttidx=8u vptridx=12u vptr=((& Z::_ZTV1Z) + 24u)
    Base (0x19a8880) alternative-path

注意“基本大小”是相同的,但“大小”是一個指針更多,並注意現在有一個vtable指針! 這反過來包含父類的構造vtable,以及所有類間魔術(構造vtable和虛擬表表(VTT)),如下所述:

http://www.cse.wustl.edu/~mdeters/seminar/fall2005/mi.html

請注意,實際的函數dispatch vtable將為空。

額外的大小可能是因為虛擬類和多重繼承分配的額外VTables( http://en.wikipedia.org/wiki/Vtable )。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM