【c++内存分布系列】单继承
父类包括成员函数、静态函数、静态方法,子类包括成员函数、静态函数、静态方法的情况与一个类时完全一致,这里就不做分析了。子类单独包含虚函数时继承无关,也不做分析了。
一、父类子类都为空
#include <cstdio> class A { }; class B: public A { }; int main(int argc, char** argv) { printf("%d\n", sizeof(B)); }
windows输出:
1
和一个空类时情况一致。
二、父类包含成员变量、子类包含成员变量或子类父类都包含成员变量
#include <cstdio> class A { public: int a; }; class B: public A { }; class AA { }; class BB: public AA { public: int b; }; class AAA { public: int a; }; class BBB: public AAA { public: int b; }; int main(int argc, char** argv) { printf("%d\n", sizeof(B)); printf("%d\n", sizeof(BB)); printf("%d\n", sizeof(BBB)); }
windows输出:
4
4
8
内存为成员变量,包括父类的。
三、父类包含虚函数,子类未实现该函数
#include <cstdio> class A { public: int a; virtual void vfun(){}; }; class B: public A { }; int main(int argc, char** argv) { printf("%d\n", sizeof(B)); B b; b.a = 0xaaaaaaaa; B* pb = &b; printf("%08x\n", pb); }
windows输出:
8
003ffe40
查看对象b的内存:
003FFE40 4C
003FFE41 57
003FFE42 22 00
003FFE44 AA
003FFE45 AA
003FFE46 AA
003FFE47 AA
查看虚表0x0022574c:
B::`vftable':
0022574C 22 11
0022574E 22 00
00225750 00 00
00225752 00 00
查看虚表指向的地址:
A::vfun:
00221122 E9 19 04 00 00 jmp A::vfun (221540h)
7: virtual void vfun(){};
00221540 55 push ebp
00221541 8B EC mov ebp,esp
00221543 81 EC CC 00 00 00 sub esp,0CCh
可知b.vfun()执行的是a的虚函数。
四、父类包含虚函数、子类实现该函数
#include <cstdio> class A { public: int a; virtual void vfun(){}; }; class B: public A { public: void vfun(){}; }; int main(int argc, char** argv) { printf("%d\n", sizeof(B)); B b; b.a = 0xaaaaaaaa; B* pb = &b; printf("%08x\n", pb); }
windows输出:
8
002bfc10
查看对象b地址内容:
002BFC10 4C
002BFC11 57
002BFC12 E7 00
002BFC14 AA
002BFC15 AA
002BFC16 AA
002BFC17 AA
查看虚表0x00e7574c:
B::`vftable':
00E7574C 27
00E7574D 11 E7
00E7574F 00 00
查看该续表中的指针0x00e71127:
B::vfun:
00E71127 E9 24 04 00 00 jmp B::vfun (0E71550h)
10: class B: public A
11: {
12: public:
13: void vfun(){};
00E71550 55 push ebp
00E71551 8B EC mov ebp,esp
00E71553 81 EC CC 00 00 00 sub esp,0CCh
可知该虚表指向类B中的实现。
五、虚继承父类,子类为空
#include <cstdio> class A { public: int a; }; class B: virtual public A { public: }; int main(int argc, char** argv) { printf("%d\n", sizeof(B)); B b; b.a = 0xaaaaaaaa; B* pb = &b; printf("%08x\n", pb); }
windows输出:
8
0036f810
查看对象b内存:
0036F810 48
0036F811 57
0036F812 34 01
0036F814 AA
0036F815 AA
0036F816 AA
0036F817 AA
内存中多了0x01345748,这个是虚基类表的指针,作用于虚函数表类似后面会详细讲。查看该虚基类表:
B::`vbtable':
01345748 00 00
0134574A 00 00
0134574c 04 00
0134574e 00 00
虚基类表内容含义后面讲。
六、虚继承父类包含虚函数
#include <cstdio> class A { public: int a; virtual void vfun(){}; }; class B: virtual public A { public: }; int main(int argc, char** argv) { printf("%d\n", sizeof(B)); B b; b.a = 0xaaaaaaaa; B* pb = &b; printf("%08x\n", pb); }
windows输出:
12
002efa64
可见内存又增加了4字节。看下对象b内存:
002EFA64 54
002EFA65 57
002EFA66 86 00
002EFA68 4C
002EFA69 57
002EFA6A 86 00
002EFA6C AA
002EFA6D AA
002EFA6E AA
002EFA6F AA
有两个指针,分别为虚基类表和虚函数表:
B::`vftable':
0086574C 22 11
0086574E 86 00
00865750 00 00
00865752 00 00
B::`vbtable':
00865754 00 00
00865756 00 00
此例中子类未实现虚函数。子类实现虚函数与四类似,只是这里多了个虚基类表,就不详细讲了。