虚基类
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()