MSVC编译器下内存模型
结论:
1、在类中存在虚函数情况下,至少有一个vfptr(虚函数指针),每虚继承一个类、产生一个vbptr(虚基类指针)
2、没有虚继承情况下,子类中的vfptr属于子类,指向的虚函数表包含父类和子类的虚函数;在有虚继承情况下,子类中存在新的虚函数情况下(不包括override父类虚函数),父类产生一个vfptr(虚函数指针)指向的虚函数表包含归属父类的虚函数和子类重写父类的虚函数。
3、在虚继承情况下,子类override重写父类的虚函数,该虚函数重写在父类的虚函数表中
class Base{
public:
virtual void funcB(){}
int aBase;
}; // 16Byte
class Derived1 :virtual public Base{
public:
void funcB(){}
virtual void funcD1(){}
int aD1;
}; // 40Byte
class Derived2 :virtual public Base{
public:
virtual void funcD2(){}
int aD2;
}; // 40Byte
class EndDerived :virtual public Derived1,virtual public Derived2{
public:
// virtual void funcEd(){} // 会产生新的vfptr 88Byte
// void funcEd(){} // 不会产生vfptr 80Byte
void funcD1(){} // 不会产生vfptr 80Byte
int aEd;
};
子类中有新虚函数情况
class EndDerived size(88):
+---
0 | {vfptr}
8 | {vbptr}
16 | aEd
| <alignment member> (size=4)
+---
+--- (virtual base Base)
24 | {vfptr}
32 | aBase
| <alignment member> (size=4)
+---
+--- (virtual base Derived1)
40 | {vfptr}
48 | {vbptr}
56 | aD1
| <alignment member> (size=4)
+---
+--- (virtual base Derived2)
64 | {vfptr}
72 | {vbptr}
80 | aD2
| <alignment member> (size=4)
+---
EndDerived::$vftable@:
| &EndDerived_meta
| 0
0 | &EndDerived::funcEd
EndDerived::$vbtable@EndDerived@:
0 | -8
1 | 16 (EndDerivedd(EndDerived+8)Base)
2 | 32 (EndDerivedd(EndDerived+8)Derived1)
3 | 56 (EndDerivedd(EndDerived+8)Derived2)
EndDerived::$vftable@Base@:
| -24
0 | &thunk: this+=40; goto Derived1::funcB
EndDerived::$vftable@Derived1@:
| -40
0 | &Derived1::funcD1
EndDerived::$vbtable@Derived1@:
0 | -8
1 | -24 (EndDerivedd(Derived1+8)Base)
EndDerived::$vftable@Derived2@:
| -64
0 | &Derived2::funcD2
EndDerived::$vbtable@Derived2@:
0 | -8
1 | -48 (EndDerivedd(Derived2+8)Base)
子类中重写父类虚函数,无新虚函数
class EndDerived size(80):
+---
0 | {vbptr}
8 | aEd
| <alignment member> (size=4)
+---
+--- (virtual base Base)
16 | {vfptr}
24 | aBase
| <alignment member> (size=4)
+---
+--- (virtual base Derived1)
32 | {vfptr}
40 | {vbptr}
48 | aD1
| <alignment member> (size=4)
+---
+--- (virtual base Derived2)
56 | {vfptr}
64 | {vbptr}
72 | aD2
| <alignment member> (size=4)
+---
EndDerived::$vbtable@EndDerived@:
0 | 0
1 | 16 (EndDerivedd(EndDerived+0)Base)
2 | 32 (EndDerivedd(EndDerived+0)Derived1)
3 | 56 (EndDerivedd(EndDerived+0)Derived2)
EndDerived::$vftable@Base@:
| -16
0 | &thunk: this+=40; goto Derived1::funcB
EndDerived::$vftable@Derived1@:
| -32
0 | &EndDerived::funcD1 // 重写的函数在相应基类的虚函数表中
EndDerived::$vbtable@Derived1@:
0 | -8
1 | -24 (EndDerivedd(Derived1+8)Base)
EndDerived::$vftable@Derived2@:
| -56
0 | &Derived2::funcD2
EndDerived::$vbtable@Derived2@:
0 | -8
1 | -48 (EndDerivedd(Derived2+8)Base)
子类中不重写父类虚函数,无新虚函数
class EndDerived size(80):
+---
0 | {vbptr}
8 | aEd
| <alignment member> (size=4)
+---
+--- (virtual base Base)
16 | {vfptr}
24 | aBase
| <alignment member> (size=4)
+---
+--- (virtual base Derived1)
32 | {vfptr}
40 | {vbptr}
48 | aD1
| <alignment member> (size=4)
+---
+--- (virtual base Derived2)
56 | {vfptr}
64 | {vbptr}
72 | aD2
| <alignment member> (size=4)
+---
EndDerived::$vbtable@EndDerived@:
0 | 0
1 | 16 (EndDerivedd(EndDerived+0)Base)
2 | 32 (EndDerivedd(EndDerived+0)Derived1)
3 | 56 (EndDerivedd(EndDerived+0)Derived2)
EndDerived::$vftable@Base@:
| -16
0 | &thunk: this+=40; goto Derived1::funcB
EndDerived::$vftable@Derived1@:
| -32
0 | &Derived1::funcD1
EndDerived::$vbtable@Derived1@:
0 | -8
1 | -24 (EndDerivedd(Derived1+8)Base)
EndDerived::$vftable@Derived2@:
| -56
0 | &Derived2::funcD2
EndDerived::$vbtable@Derived2@:
0 | -8
1 | -48 (EndDerivedd(Derived2+8)Base)
GNU编译器下内存模型
GNU编译器下共享vfptr,共用一个虚函数表,由偏移量的不同确定函数。