- 虛函數表指針:vfptr -> 指向一個虛函數表,為了解決多态問題。
- 虛基類指針:vbptr -> 指向一個虛基類表,為了解決類似棱形繼承的二義性問題。
虛繼承
#include <iostream>
using 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::[email protected]:
| &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::[email protected]@:
| &Sheep_meta
| 0
0 | &Sheep::h
Sheep::[email protected]:
0 | -4
1 | 8 (Sheepd(Sheep+4)Animal)
Sheep::[email protected]@:
| -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::[email protected]@:
| &Tuo_meta
| 0
0 | &Tuo::h
Tuo::[email protected]:
0 | -4
1 | 8 (Tuod(Tuo+4)Animal)
Tuo::[email protected]@:
| -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::[email protected]@:
| &SheepTuo_meta
| 0
0 | &SheepTuo::h
SheepTuo::[email protected]@:
| -12
0 | &thunk: this-=12; goto SheepTuo::h
SheepTuo::[email protected]@:
0 | -4
1 | 24 (SheepTuod(Sheep+4)Animal)
SheepTuo::[email protected]@:
0 | -4
1 | 12 (SheepTuod(Tuo+4)Animal)
SheepTuo::[email protected]@:
| -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
調試視窗看到的布局如下:
帶虛函數的多重繼承的記憶體布局
#include <iostream>
using 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:\Fzz\src\tectCPP\tectCPP>cl /d1reportSingleClassLayoutDerive main.cpp
用于 x86 的 Microsoft (R) C/C++ 優化編譯器 19.16.27045 版
版權所有(C) Microsoft Corporation。保留所有權利。
main.cpp
e:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.16.27023\include\xlocale(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::[email protected]@:
| &Derive_meta
| 0
0 | &Derive::f
1 | &Base1::g
2 | &Base1::h
3 | &Derive::g1
4 | &Derive::h1
5 | &Derive::j1
Derive::[email protected]@:
| -8
0 | &thunk: this-=8; goto Derive::f
1 | &Base2::g
2 | &Base2::h
Derive::[email protected]@:
| -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
參考
圖文詳解虛繼承的實作原理(記憶體布局分析)