跳转至

虚基类

Example1

C++
class X {
public:
  double i;
};

class A: public virtual X {
public:
  double j;
};

class B: public virtual X {
public:
  double k;
};

class C: public A, public B {
  double l;
};

void foo() {
  C c;
}

Result

1 gcc

Bash
g++ -fdump-class-hierarchy base.cpp -c
cat base.cpp.002t.class

Class X
   size=8 align=8
   base size=8 base align=8
X (0x0x3fff7a2704e0) 0

Vtable for A
A::_ZTV1A: 3u entries
0     16u
8     (int (*)(...))0
16    (int (*)(...))(& _ZTI1A)

VTT for A
A::_ZTT1A: 1u entries
0     ((& A::_ZTV1A) + 24u)

Class A
   size=24 align=8
   base size=16 base align=8
A (0x0x3fff7a2600d0) 0
    vptridx=0u vptr=((& A::_ZTV1A) + 24u)
  X (0x0x3fff7a270540) 16 virtual
      vbaseoffset=-24

Vtable for B
B::_ZTV1B: 3u entries
0     16u
8     (int (*)(...))0
16    (int (*)(...))(& _ZTI1B)

VTT for B
B::_ZTT1B: 1u entries
0     ((& B::_ZTV1B) + 24u)

Class B
   size=24 align=8
   base size=16 base align=8
B (0x0x3fff7a260138) 0
    vptridx=0u vptr=((& B::_ZTV1B) + 24u)
  X (0x0x3fff7a2705a0) 16 virtual
      vbaseoffset=-24

Vtable for C
C::_ZTV1C: 6u entries
0     40u
8     (int (*)(...))0
16    (int (*)(...))(& _ZTI1C)
24    24u
32    (int (*)(...))-16
40    (int (*)(...))(& _ZTI1C)

Construction vtable for A (0x0x3fff7a2601a0 instance) in C
C::_ZTC1C0_1A: 3u entries
0     40u
8     (int (*)(...))0
16    (int (*)(...))(& _ZTI1A)

Construction vtable for B (0x0x3fff7a260208 instance) in C
C::_ZTC1C16_1B: 3u entries
0     24u
8     (int (*)(...))0
16    (int (*)(...))(& _ZTI1B)

VTT for C
C::_ZTT1C: 4u entries
0     ((& C::_ZTV1C) + 24u)
8     ((& C::_ZTC1C0_1A) + 24u)
16    ((& C::_ZTC1C16_1B) + 24u)
24    ((& C::_ZTV1C) + 48u)

Class C
   size=48 align=8
   base size=40 base align=8
C (0x0x3fff82e00e70) 0
    vptridx=0u vptr=((& C::_ZTV1C) + 24u)
  A (0x0x3fff7a2601a0) 0
      primary-for C (0x0x3fff82e00e70)
      subvttidx=8u
    X (0x0x3fff7a270600) 40 virtual
        vbaseoffset=-24
  B (0x0x3fff7a260208) 16
      subvttidx=16u vptridx=24u vptr=((& C::_ZTV1C) + 48u)
    X (0x0x3fff7a270600) alternative-path

2. clang

Bash
clang++ -Xclang -fdump-record-layouts  base.cpp -c

*** Dumping AST Record Layout
         0 | class X
         0 |   double i
           | [sizeof=8, dsize=8, align=8,
           |  nvsize=8, nvalign=8]

*** Dumping AST Record Layout
         0 | class A
         0 |   (A vtable pointer)
         8 |   double j
        16 |   class X (virtual base)
        16 |     double i
           | [sizeof=24, dsize=24, align=8,
           |  nvsize=16, nvalign=8]

*** Dumping AST Record Layout
         0 | class B
         0 |   (B vtable pointer)
         8 |   double k
        16 |   class X (virtual base)
        16 |     double i
           | [sizeof=24, dsize=24, align=8,
           |  nvsize=16, nvalign=8]

*** Dumping AST Record Layout
         0 | class C
         0 |   class A (primary base)
         0 |     (A vtable pointer)   // 8
         8 |     double j             // 8
        16 |   class B (base)
        16 |     (B vtable pointer)   // 8
        24 |     double k             // 8
        32 |   double l               // 8
        40 |   class X (virtual base)
        40 |     double i             // 8
           | [sizeof=48, dsize=48, align=8,
           |  nvsize=40, nvalign=8]

C有2个虚表指针(A B),指向同一个虚表

Bash
Vtable for 'C' (6 entries).
   0 | vbase_offset (40)
   1 | offset_to_top (0)
   2 | C RTTI
       -- (A, 0) vtable address --
       -- (C, 0) vtable address --
   3 | vbase_offset (24)
   4 | offset_to_top (-16)
   5 | C RTTI
       -- (B, 16) vtable address --

Virtual base offset offsets for 'C' (1 entry).
   X | -24


Construction vtable for ('A', 0) in 'C' (3 entries).
   0 | vbase_offset (40)
   1 | offset_to_top (0)
   2 | A RTTI
       -- (A, 0) vtable address --

Construction vtable for ('B', 16) in 'C' (3 entries).
   0 | vbase_offset (24)
   1 | offset_to_top (0)
   2 | B RTTI
       -- (B, 16) vtable address --

Example2

C++
class X {
public:
  double i;
  virtual void fooX();
};

class A: public virtual X {
public:
  double j;
  virtual void fooA();
};

class B: public virtual X {
public:
  double k;
  virtual void fooB();
};

class C: public A, public B {
  double l;
  virtual void fooC();
};

void foo() {
  C c;
}

Result:

Bash
g++ -fdump-class-hierarchy test.cpp -c
cat test.cpp.002t.class

Vtable for X
X::_ZTV1X: 3u entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI1X)
16    (int (*)(...))X::fooX

Class X
   size=16 align=8
   base size=16 base align=8
X (0x0x3fffa69204e0) 0
    vptr=((& X::_ZTV1X) + 16u)

Vtable for A
A::_ZTV1A: 8u entries
0     16u
8     (int (*)(...))0
16    (int (*)(...))(& _ZTI1A)
24    (int (*)(...))A::fooA
32    0u
40    (int (*)(...))-16
48    (int (*)(...))(& _ZTI1A)
56    (int (*)(...))X::fooX

VTT for A
A::_ZTT1A: 2u entries
0     ((& A::_ZTV1A) + 24u)
8     ((& A::_ZTV1A) + 56u)

Class A
   size=32 align=8
   base size=16 base align=8
A (0x0x3fffa69100d0) 0
    vptridx=0u vptr=((& A::_ZTV1A) + 24u)
  X (0x0x3fffa6920540) 16 virtual
      vptridx=8u vbaseoffset=-24 vptr=((& A::_ZTV1A) + 56u)

Vtable for B
B::_ZTV1B: 8u entries
0     16u
8     (int (*)(...))0
16    (int (*)(...))(& _ZTI1B)
24    (int (*)(...))B::fooB
32    0u
40    (int (*)(...))-16
48    (int (*)(...))(& _ZTI1B)
56    (int (*)(...))X::fooX

VTT for B
B::_ZTT1B: 2u entries
0     ((& B::_ZTV1B) + 24u)
8     ((& B::_ZTV1B) + 56u)

Class B
   size=32 align=8
   base size=16 base align=8
B (0x0x3fffa69101a0) 0
    vptridx=0u vptr=((& B::_ZTV1B) + 24u)
  X (0x0x3fffa69205a0) 16 virtual
      vptridx=8u vbaseoffset=-24 vptr=((& B::_ZTV1B) + 56u)

Vtable for C
C::_ZTV1C: 13u entries
0     40u
8     (int (*)(...))0
16    (int (*)(...))(& _ZTI1C)
24    (int (*)(...))A::fooA
32    (int (*)(...))C::fooC
40    24u
48    (int (*)(...))-16
56    (int (*)(...))(& _ZTI1C)
64    (int (*)(...))B::fooB
72    0u
80    (int (*)(...))-40
88    (int (*)(...))(& _ZTI1C)
96    (int (*)(...))X::fooX

Construction vtable for A (0x0x3fffa6910270 instance) in C
C::_ZTC1C0_1A: 8u entries
0     40u
8     (int (*)(...))0
16    (int (*)(...))(& _ZTI1A)
24    (int (*)(...))A::fooA
32    0u
40    (int (*)(...))-40
48    (int (*)(...))(& _ZTI1A)
56    (int (*)(...))X::fooX

Construction vtable for B (0x0x3fffa69102d8 instance) in C
C::_ZTC1C16_1B: 8u entries
0     24u
8     (int (*)(...))0
16    (int (*)(...))(& _ZTI1B)
24    (int (*)(...))B::fooB
32    0u
40    (int (*)(...))-24
48    (int (*)(...))(& _ZTI1B)
56    (int (*)(...))X::fooX

VTT for C
C::_ZTT1C: 7u entries
0     ((& C::_ZTV1C) + 24u)
8     ((& C::_ZTC1C0_1A) + 24u)
16    ((& C::_ZTC1C0_1A) + 56u)
24    ((& C::_ZTC1C16_1B) + 24u)
32    ((& C::_ZTC1C16_1B) + 56u)
40    ((& C::_ZTV1C) + 96u)
48    ((& C::_ZTV1C) + 64u)

Class C
   size=56 align=8
   base size=40 base align=8
C (0x0x3fffaf4b0ee0) 0
    vptridx=0u vptr=((& C::_ZTV1C) + 24u)
  A (0x0x3fffa6910270) 0
      primary-for C (0x0x3fffaf4b0ee0)
      subvttidx=8u
    X (0x0x3fffa6920600) 40 virtual
        vptridx=40u vbaseoffset=-24 vptr=((& C::_ZTV1C) + 96u)
  B (0x0x3fffa69102d8) 16
      subvttidx=24u vptridx=48u vptr=((& C::_ZTV1C) + 64u)
    X (0x0x3fffa6920600) alternative-path

clang

Bash
clang++ -Xclang -fdump-record-layouts test.cpp -c

*** Dumping AST Record Layout
         0 | class X
         0 |   (X vtable pointer)
         8 |   double i
           | [sizeof=16, dsize=16, align=8,
           |  nvsize=16, nvalign=8]

*** Dumping AST Record Layout
         0 | class A
         0 |   (A vtable pointer)
         8 |   double j
        16 |   class X (virtual base)
        16 |     (X vtable pointer)
        24 |     double i
           | [sizeof=32, dsize=32, align=8,
           |  nvsize=16, nvalign=8]

*** Dumping AST Record Layout
         0 | class B
         0 |   (B vtable pointer)
         8 |   double k
        16 |   class X (virtual base)
        16 |     (X vtable pointer)
        24 |     double i
           | [sizeof=32, dsize=32, align=8,
           |  nvsize=16, nvalign=8]

*** Dumping AST Record Layout
         0 | class C
         0 |   class A (primary base)
         0 |     (A vtable pointer)      // 8
         8 |     double j                // 8
        16 |   class B (base)
        16 |     (B vtable pointer)      // 8
        24 |     double k                // 8
        32 |   double l                  // 8
        40 |   class X (virtual base)
        40 |     (X vtable pointer)      // 8
        48 |     double i                // 8
           | [sizeof=56, dsize=56, align=8,
           |  nvsize=40, nvalign=8]

3个虚表指针(A B X),因为X也有虚函数

Bash
clang++ -Xclang -fdump-vtable-layouts test.cpp -c

Vtable for 'C' (13 entries).
   0 | vbase_offset (40)
   1 | offset_to_top (0)
   2 | C RTTI
       -- (A, 0) vtable address --
       -- (C, 0) vtable address --
   3 | void A::fooA()
   4 | void C::fooC()
   5 | vbase_offset (24)
   6 | offset_to_top (-16)
   7 | C RTTI
       -- (B, 16) vtable address --
   8 | void B::fooB()
   9 | vcall_offset (0)
  10 | offset_to_top (-40)
  11 | C RTTI
       -- (X, 40) vtable address --
  12 | void X::fooX()

Virtual base offset offsets for 'C' (1 entry).
   X | -24

VTable indices for 'C' (1 entries).
   1 | void C::fooC()

Vtable for 'X' (3 entries).
   0 | offset_to_top (0)
   1 | X RTTI
       -- (X, 0) vtable address --
   2 | void X::fooX()

VTable indices for 'X' (1 entries).
   0 | void X::fooX()