- 虚函数表指针:vfptr -> 指向一个虚函数表,为了解决多态问题。
- 虚基类指针:vbptr -> 指向一个虚基类表,为了解决类似棱形继承的二义性问题。
#includeusing namespace std; class Animal { public: virtual ~Animal() = default; int animal; virtual void f() { cout << "Animal::f()" << endl; } virtual void g() { cout << "Animal::g()" << endl; } }; //这里添加的virtual对于Sheep和Tuo本身没影响,只对他们的子类有影响。 class Sheep : virtual public Animal { public: int sheep; virtual void f() { cout << "sheep::f()" << endl; } virtual void g() { cout << "sheep::g()" << endl; } virtual void h() { cout << "sheep::h()" << endl; } }; class Tuo : virtual public Animal { public: int tuo; virtual void f() { cout << "Tuo::f()" << endl; } virtual void g() { cout << "Tuo::g()" << endl; } virtual void h() { cout << "Tuo::h()" << endl; } }; class SheepTuo :public Sheep, public Tuo { public: int sheep_tuo; virtual void f() { cout << "SheepTuo::f()" << endl; } virtual void g() { cout << "SheepTuo::g()" << endl; } virtual void h() { cout << "SheepTuo::h()" << endl; } }; int main() { SheepTuo st; cout << "sizeof(SheepTuo) is " << sizeof(SheepTuo) << endl; return 0; }
继承关系图
打开 工具->Visual studio命令提示 工具,cd 到源码所在的路径下,输入cl /d1reportSingleClassLayout"要查看的类名" “文件名”,在这里就是cl /d1reportSingleClassLayoutSheepTuo main.cpp。可以看到当前类内存的结构。(编译后才能查看到内存分布)。
- Animal的内存布局:
class Animal size(8):
+---
0 | {vfptr}
4 | animal
+---
Animal::$vftable@:
| &Animal_meta
| 0
0 | &Animal::{dtor}
1 | &Animal::f
2 | &Animal::g
Animal::{dtor} this adjustor: 0
Animal::f this adjustor: 0
Animal::g this adjustor: 0
Animal::__delDtor this adjustor: 0
Animal::__vecDelDtor this adjustor: 0
- Sheep的内存布局(虚继承会多出一个vbptr,并且自身的类布局会放到最前面,从而会有自身的vfptr)
class Sheep size(20):
+---
0 | {vfptr}
4 | {vbptr}
8 | sheep
+---
+--- (virtual base Animal)
12 | {vfptr}
16 | animal
+---
Sheep::$vftable@Sheep@:
| &Sheep_meta
| 0
0 | &Sheep::h
Sheep::$vbtable@:
0 | -4
1 | 8 (Sheepd(Sheep+4)Animal)
Sheep::$vftable@Animal@:
| -12
0 | &Sheep::{dtor}
1 | &Sheep::f
2 | &Sheep::g
Sheep::{dtor} this adjustor: 12
Sheep::f this adjustor: 12
Sheep::g this adjustor: 12
Sheep::h this adjustor: 0
Sheep::__delDtor this adjustor: 12
Sheep::__vecDelDtor this adjustor: 12
vbi: class offset o.vbptr o.vbte fVtorDisp
Animal 12 4 4 0
- Tuo的内存布局
class Tuo size(20):
+---
0 | {vfptr}
4 | {vbptr}
8 | tuo
+---
+--- (virtual base Animal)
12 | {vfptr}
16 | animal
+---
Tuo::$vftable@Tuo@:
| &Tuo_meta
| 0
0 | &Tuo::h
Tuo::$vbtable@:
0 | -4
1 | 8 (Tuod(Tuo+4)Animal)
Tuo::$vftable@Animal@:
| -12
0 | &Tuo::{dtor}
1 | &Tuo::f
2 | &Tuo::g
Tuo::{dtor} this adjustor: 12
Tuo::f this adjustor: 12
Tuo::g this adjustor: 12
Tuo::h this adjustor: 0
Tuo::__delDtor this adjustor: 12
Tuo::__vecDelDtor this adjustor: 12
vbi: class offset o.vbptr o.vbte fVtorDisp
Animal 12 4 4 0
- SheepTuo的内存布局,由于它的继承并非虚继承,所有自身的类布局放在最后,且没有vbptr.
class SheepTuo size(36):
+---
0 | +--- (base class Sheep)
0 | | {vfptr}
4 | | {vbptr}
8 | | sheep
| +---
12 | +--- (base class Tuo)
12 | | {vfptr}
16 | | {vbptr}
20 | | tuo
| +---
24 | sheep_tuo
+---
+--- (virtual base Animal)
28 | {vfptr}
32 | animal
+---
SheepTuo::$vftable@Sheep@:
| &SheepTuo_meta
| 0
0 | &SheepTuo::h
SheepTuo::$vftable@Tuo@:
| -12
0 | &thunk: this-=12; goto SheepTuo::h
SheepTuo::$vbtable@Sheep@:
0 | -4
1 | 24 (SheepTuod(Sheep+4)Animal)
SheepTuo::$vbtable@Tuo@:
0 | -4
1 | 12 (SheepTuod(Tuo+4)Animal)
SheepTuo::$vftable@Animal@:
| -28
0 | &SheepTuo::{dtor}
1 | &SheepTuo::f
2 | &SheepTuo::g
SheepTuo::f this adjustor: 28
SheepTuo::g this adjustor: 28
SheepTuo::h this adjustor: 0
SheepTuo::{dtor} this adjustor: 28
SheepTuo::__delDtor this adjustor: 28
SheepTuo::__vecDelDtor this adjustor: 28
vbi: class offset o.vbptr o.vbte fVtorDisp
Animal 28 4 4 0
Microsoft (R) Incremental linker Version 14.16.27045.0
Copyright (C) Microsoft Corporation. All rights reserved.
/out:main.exe
main.obj
调试窗口看到的布局如下:
#includeusing namespace std; class base1 { public: //三个虚函数 virtual void f() { cout << "base1::f" << endl; } virtual void g() { cout << "base1::g" << endl; } virtual void h() { cout << "base1::h" << endl; } int base1; }; class base2 { public: //三个虚函数 virtual void f() { cout << "base2::f" << endl; } virtual void g() { cout << "base2::g" << endl; } virtual void h() { cout << "base2::h" << endl; } int base2; }; class base3 { public: //三个虚函数 virtual void f() { cout << "base3::f" << endl; } virtual void g() { cout << "base3::g" << endl; } virtual void h() { cout << "base3::h" << endl; } int base3; }; class Derive :public base1, public base2, public base3 { public: virtual void f() override { cout << "Derive::f" << endl; } //唯一一个覆盖的子类函数 virtual void g1() { cout << "Derive::g1" << endl; } virtual void h1() { cout << "Derive::h1" << endl; } virtual void j1() { cout << "Derive::h1" << endl; } int derive; }; int main() { Derive d; cout << "sizeof d: " << sizeof(d) << endl; return 0; }
其内存布局如下图所示:
红框框中的部分表明虚函数表的大小,包含结束标志。
D:FzzsrctectCPPtectCPP>cl /d1reportSingleClassLayoutDerive main.cpp
用于 x86 的 Microsoft (R) C/C++ 优化编译器 19.16.27045 版
版权所有(C) Microsoft Corporation。保留所有权利。
main.cpp
e:Program Files (x86)Microsoft Visual Studio2017EnterpriseVCToolsMSVC14.16.27023includexlocale(319): warning C4530: 使用了 C++ 异常处理程序,但未启用展开语义。请指定 /EHsc
class Derive size(28):
+---
0 | +--- (base class base1)
0 | | {vfptr}
4 | | base1
| +---
8 | +--- (base class base2)
8 | | {vfptr}
12 | | base2
| +---
16 | +--- (base class base3)
16 | | {vfptr}
20 | | base3
| +---
24 | derive
+---
Derive::$vftable@base1@:
| &Derive_meta
| 0
0 | &Derive::f
1 | &base1::g
2 | &base1::h
3 | &Derive::g1
4 | &Derive::h1
5 | &Derive::j1
Derive::$vftable@base2@:
| -8
0 | &thunk: this-=8; goto Derive::f
1 | &base2::g
2 | &base2::h
Derive::$vftable@base3@:
| -16
0 | &thunk: this-=16; goto Derive::f
1 | &base3::g
2 | &base3::h
Derive::f this adjustor: 0
Derive::g1 this adjustor: 0
Derive::h1 this adjustor: 0
Derive::j1 this adjustor: 0
Microsoft (R) Incremental linker Version 14.16.27045.0
Copyright (C) Microsoft Corporation. All rights reserved.
/out:main.exe
main.obj
参考
图文详解虚继承的实现原理(内存布局分析)



