C++ - 对象模型之 内存布局
2013-03-03 21:44
483 查看
C++对象模型目录
C++
- 对象模型之 编译器何时才会自行添加构造函数
C++
- 对象模型之 内存布局
C++
- 对象模型之 成员函数调用
C++
- 对象模型之 构造和析构函数都干了什么
C++
- 对象模型之 类对象在执行时是如何生成的
C++
- 对象模型之 模板、异常、RTTI的实现
C++ - 对象模型之 内存布局
class的static member不属于任何类对象,它保存在数据段,下面我们将对nonestatic member进行分析。
问题:
1. 为什么第5个字节,即vbase前面是一个NULL字节,它的作用是什么?
2. who函数应该怎么索引到?
结果:
father(0x0012FF5C) child1(0x0012FF4C) child2(0x0012FF3C)
father vptr is 0x004157B0
child1 vptr is 0x00415758
child2 vptr is 0x00415758
分析:
我们可以看到 child1和child2同属于Child类型,他们的vptr地址是一样的;而father类型是Father,它的vptr是另外一个地址。
结果:
father Size(4) child1 Size(12) child2 Size(12)
child1 vbase_pointer is 0x00415768, age is 10
child2 vbase_pointer is 0x00415768, age is 10
Child object vbase offset is 8
分析:
child1和child2指向virtual base class的指针一样的,并且该指针也是指向数据段的,所以同样类型的对象的虚基类的offset是一样的。
结果:
child(0x0012FF58) size(12)
child.Father::age(0x0012FF5C)
child.age(0x0012FF60)
分析:
如果只考虑字节对齐,应该是如下布局:| vptr 4B | Father age 1B | Child age 1B | padding 2B | 共8字节
而布局实际如下:| vptr 4B | Father age 1B | padding 3B | Child age 1B | padding 3B | 共12字节
其实,这样是完全可以理解的,因为Father的对象内存布局如下:| vptr 4B | Father age 1B | padding 3B | 共8字节,那么如果将Father的对象复制到Child对象空间,那么如果按照上面第一种情况,那么Child对象的Child age数据就会被Father对象的padding数据给覆盖掉,造成了数据丢失,所以这样是不合适的。
Child Size : 40B
|Father vptr|
|Father_vbase_pointer|
|Father::age|
|Mother vptr|
|Mother_vbase_pointer|
|Mother::age|
|Child::age|
|NULL|
|GrandFather vptr|
|GrandFather::age|
里面有两个指向virtual base class的指针Father_vbase_pointer和Mother_vbase_pointer。
Father Vbase table
|Father vptr offsetfrom Father_vbase_pointer | -4
|vbase offset from Father_vbase_pointer| 28
Mother Vbase table
|Mother vptr offsetfrom Mother_vbase_pointer | -4
|vbase offset from Mother_vbase_pointer | 16
这样的指针有两个作用
1. 能够通过偏移找到vtbl
2. 能够通过偏移找到virtual base class subobject
C++
- 对象模型之 编译器何时才会自行添加构造函数
C++
- 对象模型之 内存布局
C++
- 对象模型之 成员函数调用
C++
- 对象模型之 构造和析构函数都干了什么
C++
- 对象模型之 类对象在执行时是如何生成的
C++
- 对象模型之 模板、异常、RTTI的实现
C++ - 对象模型之 内存布局
class的static member不属于任何类对象,它保存在数据段,下面我们将对nonestatic member进行分析。
基本内存布局
空类
空类 | #include <stdio.h> class Child{ }; int main(){ Child child1; Child child2; printf("child1 : address(0x%p) size(%d)\n", &child1,sizeof(child1)); printf("child2 : address(0x%p) size(%d)\n", &child2,sizeof(child2)); printf("child1.char : 0x%02x\n",child1); printf("child2.char : 0x%02x\n",child2); } | ||
| |||
X86 VC++ | X86 g++ | ||
打印结果 | child1 : address(0x0012FF63) size(1) child2 : address(0x0012FF57) size(1) child1.char : 0xcc child2.char : 0xcc | 打印结果 | |
内存布局 | Child Size: 1B |char| | 内存布局 | |
Vtbl | | Vtbl | |
其他 | | 其他 | |
无继承
无继承 | #include <stdio.h> class Child{ public: int age; }; int main(){ Child child1; printf("child1 : address(0x%p) size(%d)\n", &child1,sizeof(child1)); printf("child1.age : address(0x%p)\n", &child1.age); } | ||
| |||
X86 VC++ | X86 g++ | ||
打印结果 | child1 : address(0x0012FF60) size(4) child1.age : address(0x0012FF60) | 打印结果 | |
内存布局 | Child Size:4B |age| | 内存布局 | |
Vtbl | | Vtbl | |
其他 | | 其他 | |
无继承&多态
无继承&多态 | #include <stdio.h> typedef void(*Fun)(void); class Child{ public: int age; Child():age(8){} virtual void who(){ printf("I am child\n");} virtual void study(){ printf("study...\n");} }; int main(){ Child child; Fun fun = NULL; int * vtbl = (int *)(*((int*)&child)); printf("child(0x%p) : size(%d)\n",&child,sizeof(child)); printf("child[0] is vptr, points to vtbl 0x%p\n",vtbl); printf("child[1] is Age : %d\n", ((int *)(&child))[1]); for (int i=0; (Fun)vtbl[i]!=NULL;i++){ fun = (Fun)vtbl[i]; printf("vtbl[%d] : ",i); fun(); } } | ||
| |||
X86 VC++ | X86 g++ | ||
打印结果 | child(0x0012FF5C) : size(8) child[0] is vptr, points to vtbl 0x0041587C child[1] is Age : 8 vtbl[0] : I am child vtbl[1] : study... | 打印结果 | |
内存布局 | Child Size:8B |vptr|age| | 内存布局 | |
Vtbl | |Child::who()| |Child::study()| | Vtbl | |
其他 | Vtbl存在堆上 | 其他 | |
单一继承
单一继承 | #include <stdio.h> typedef void(*Fun)(void); class GrandFather{ public: GrandFather():age(60){} void fishing(){ printf("GrandFather go to fishing...\n");} int age; }; class Father:public GrandFather{ public: Father():age(36){} void cutting(){ printf("Father go to cutting...\n");} int age; }; class Child:public Father{ public: Child():age(8){} void studying(){ printf("Child go to studying...\n");} int age; }; int main(){ Child child; printf("child(0x%p) : size(%d)\n",&child,sizeof(child)); printf("child[0] is GrandFather : %d\n", ((int *)(&child))[0]); printf("child[1] is Father : %d\n", ((int *)(&child))[1]); printf("child[2] is child : %d\n", ((int *)(&child))[2]); } | ||
GrandFather ↑ Father ↑ Child | |||
X86 VC++ | X86 g++ | ||
打印结果 | child(0x0012FF58) : size(12) child[0] is GrandFather : 60 child[1] is Father : 36 child[2] is child : 8 | 打印结果 | |
内存布局 | Child Size:12B |GrandFather::age| |Father::age| |Child::age| | 内存布局 | |
Vtbl | | Vtbl | |
其他 | | 其他 | |
[b]单一继承&多态[/b]
单一继承&多态 | #include <stdio.h> typedef void(*Fun)(void); class GrandFather{ public: GrandFather():age(60){} virtual void who(){ printf("I am GrandFather\n");} virtual void fishing(){ printf("GrandFather go to fishing...\n");} virtual void hungry(){ printf("GrandFather is hungry\n");} int age; }; class Father:public GrandFather{ public: Father():age(36){} virtual void who(){ printf("I am Father\n");} virtual void cutting(){ printf("Father go to cutting...\n");} virtual void hungry(){ printf("Father is hungry\n");} int age; }; class Child : public Father{ public: Child():age(8){} virtual void who(){ printf("I am Child\n");} virtual void studying(){ printf("Child go to studying...\n");} virtual void hungry(){ printf("Child is hungry\n");} int age; }; int main(){ Child child; Fun fun = NULL; int * vtbl = (int *)(*((int*)&child)); printf("child(0x%p) : size(%d)\n",&child,sizeof(child)); printf("child[0] is vptr, points to vtbl 0x%p\n",vtbl); printf("child[1] is GrandFather : %d\n", ((int *)(&child))[1]); printf("child[2] is Father : %d\n", ((int *)(&child))[2]); printf("child[3] is child : %d\n", ((int *)(&child))[3]); for (int i=0; (Fun)vtbl[i]!=NULL;i++){ fun = (Fun)vtbl[i]; printf("vtbl[%d] : ",i); fun(); } } | ||
GrandFather ↑ Father ↑ Child | |||
X86 VC++ | X86 g++ | ||
打印结果 | child(0x0012FF54) : size(16) child[0] is vptr, points to vtbl 0x004157FC child[1] is GrandFather : 60 child[2] is Father : 36 child[3] is child : 8 vtbl[0] : I am Child vtbl[1] : GrandFather go to fishing... vtbl[2] : Child is hungry vtbl[3] : Father go to cutting... vtbl[4] : Child go to studying... | 打印结果 | |
内存布局 | Child Size:16B |vptr| |GrandFather::age| |Father::age| |Child::age| | 内存布局 | |
Vtbl | |Child::who()| |GrandFather::fishing()| | Child::hungry()| |Father::cutting()| |Child::studying()| | Vtbl | |
其他 | 虚函数顺序是从base开始遍历 | 其他 | |
多重继承
多重继承 | #include <stdio.h> class GrandFather{ public: GrandFather():age(60){} int age; }; class Grandad{ public: Grandad():age(57){} int age; }; class Father:public GrandFather{ public: Father():age(36){} int age; }; class Mother:public Grandad{ public: Mother():age(34){} int age; }; class Child : public Father, public Mother{ public: Child():age(8){} int age; }; int main(){ Child child; int* pchild = (int *)&child; printf("child(0x%p) : size(%d)\n",&child,sizeof(child)); printf("child[0] GrandFather : %d\n",pchild[0]); printf("child[1] Father : %d\n",pchild[1]); printf("child[2] Grandad : %d\n",pchild[2]); printf("child[3] Mother : %d\n",pchild[3]); printf("child[4] Child : %d\n",pchild[4]); } | ||
GrandFathe Grandad ^ ^ Father Mother ^ Child | |||
X86 VC++ | X86 g++ | ||
打印结果 | child(0x0012FF50) : size(20) child[0] : 60 child[1] : 36 child[2] : 57 child[3] : 34 child[4] : 8 | 打印结果 | |
内存布局 | Child Size:20B |GrandFather::age| |Father::age| |Grandad::age| |Mother::age| |Child::age| | 内存布局 | |
Vtbl | | Vtbl | |
其他 | | 其他 | |
多重继承&多态
多重继承&多态 | #include <stdio.h> typedef void(*Fun)(void); class GrandFather{ public: GrandFather():age(60){} virtual void who(){ printf("I am GrandFather\n");} virtual void fishing(){ printf("GrandFather go to fishing...\n");} virtual void hungry(){ printf("GrandFather is hungry\n");} int age; }; class Grandad{ public: Grandad():age(57){} virtual void who(){ printf("I am Grandad\n");} virtual void chessing(){ printf("Grandad go to chessing...\n");} virtual void hungry(){ printf("Grandad is hungry\n");} int age; }; class Father:public GrandFather{ public: Father():age(36){} virtual void who(){ printf("I am Father\n");} virtual void cutting(){ printf("Father go to cutting...\n");} virtual void hungry(){ printf("Father is hungry\n");} int age; }; class Mother:public Grandad{ public: Mother():age(34){} virtual void who(){ printf("I am Mother\n");} virtual void sewing(){ printf("Mother go to sewing...\n");} virtual void hungry(){ printf("Mother is hungry\n");} int age; }; class Child : public Father, public Mother{ public: Child():age(8){} virtual void who(){ printf("I am Child\n");} virtual void studying(){ printf("Child go to studying...\n");} virtual void hungry(){ printf("Child is hungry\n");} int age; }; int main(){ Child child; int* pchild = (int *)&child; printf("child(0x%p) : size(%d)\n",&child,sizeof(child)); printf("child[0] vptr1 : 0x%p\n",pchild[0]); printf("child[1] GrandFather : %d\n",pchild[1]); printf("child[2] Father : %d\n",pchild[2]); printf("child[3] vptr2 : 0x%p\n",pchild[3]); printf("child[4] Grandad : %d\n",pchild[4]); printf("child[5] Mother : %d\n",pchild[5]); printf("child[6] Child : %d\n",pchild[6]); Fun fun = NULL; int * vtbl1 = (int *)pchild[0]; for (int i=0; (Fun)vtbl1[i]!=NULL; i++){ fun = (Fun)vtbl1[i]; printf("vtbl1[%d] : ", i); fun(); } int * vtbl2 = (int *)pchild[3]; for (int i=0; (Fun)vtbl2[i]!=NULL; i++){ fun = (Fun)vtbl2[i]; printf("vtbl2[%d] : ", i); fun(); } } | ||
GrandFathe Grandad ^ ^ Father Mother ^ Child | |||
X86 VC++ | X86 g++ | ||
打印结果 | child(0x0012FF48) : size(28) child[0] vptr1 : 0x00416864 child[1] GrandFather : 60 child[2] Father : 36 child[3] vptr2 : 0x0041684C child[4] Grandad : 57 child[5] Mother : 34 child[6] Child : 8 vtbl1[0] : I am Child vtbl1[1] : GrandFather go to fishing... vtbl1[2] : Child is hungry vtbl1[3] : Father go to cutting... vtbl1[4] : Child go to studying... vtbl2[0] : I am Child vtbl2[1] : Grandad go to chessing... vtbl2[2] : Child is hungry vtbl2[3] : Mother go to sewing... | 打印结果 | |
内存布局 | Child Size:28B |vptr1| |GrandFather::age| |Father::age| |vptr2| |Grandad::age| |Mother::age| |Child::age| | 内存布局 | |
Vtbl | Vtbl1: |Child::who()| |GrandFather::age| |Child::hungry()| |Father::cutting()| |Child::studying()| Vtbl2: |Child::who()| |Grandad::chessing()| |Child::hungry()| |Mother::sewing()| | Vtbl | |
其他 | Child的独有虚函数,如studying,只在base1的vtbl进行记录。 | 其他 | |
[b]单一虚拟继承[/b]
单一虚拟继承 | #include <stdio.h> typedef void(*Fun)(void); class GrandFather{ public: GrandFather():age(60){} int age; }; class Father : virtual public GrandFather{ public: Father():age(36){} int age; }; class Child : public Father{ public: Child():age(8){} int age; }; int main(){ Child child; int* pchild = (int *)&child; int* pFather = (int*)pchild[0];//指向virtual base subobject的指针 printf("child(0x%p) : size(%d)\n",&child,sizeof(child)); printf("child[0] pFather : 0x%p\n",pchild[0]); printf("child[1] Father : %d\n",pchild[1]); printf("child[2] Child : %d\n",pchild[2]); /*通过pchild和pFather获得偏移量都可以获得virtual base 数据*/ printf("child[3] GrandFather : %d %d\n", pchild[3], *(int*)(((char *)pchild)+pFather[1])); printf("pFather[0] : 0x%p\n",pFather[0], pFather[1]); printf("pFather[1] Offset : %d\n", pFather[1]); } | ||
GrandFather ^ Father ^ Child | |||
X86 VC++ | X86 g++ | ||
打印结果 | child(0x0012FF54) : size(16) child[0] pFather : 0x00415758 child[1] Father : 36 child[2] Child : 8 child[3] GrandFather : 60 60 pFather[0] : 0x00000000 pFather[1] Offset : 12 | 打印结果 | |
内存布局 | Child Size:16B |vbase_pointer| pointer to vbase |Father::age| |Child::age| |GrandFather::age| | 内存布局 | |
vbase | |vptr offset from vbase_pointer| |vbase offset from vbase_pointer| | | |
Vtbl | | Vtbl | |
其他 | 寻址Virtual base object和Derivedvptr是通过offset来得到的 | 其他 | |
[b][b]单一虚拟继承&多态[/b][/b]
[b][b]案例一[/b][/b]
虚基类无虚函数。单一虚拟继承&多态 一 | #include <stdio.h> typedef void(*Fun)(void); class GrandFather{ public: GrandFather():age(60){} void fishing(){ printf("GrandFather go to fishing...\n");} int age; }; class Father : virtual public GrandFather{ public: Father():age(36){} virtual void who(){ printf("I am Father\n");} virtual void cutting(){ printf("Father go to cutting...\n");} virtual void hungry(){ printf("Father is hungry\n");} int age; }; class Child : public Father{ public: Child():age(8){} virtual void who(){ printf("I am Child\n");} virtual void studying(){ printf("Child go to studying...\n");} virtual void hungry(){ printf("Child is hungry\n");} int age; }; int main(){ Child child; Fun fun = NULL; int* pchild = (int *)&child; int* vbase_pointer = (int*)pchild[1]; int* vtbl = (int *)pchild[0]; printf("child(0x%p) : size(%d)\n",&child,sizeof(child)); printf("child[0] vtbl : 0x%p\n", vtbl); printf("child[1] vbase_pointer : 0x%p\n", vbase_pointer); printf("child[2] Father : %d\n", pchild[2]); printf("child[3] Child : %d\n", pchild[3]); printf("child[4] GrandFather : %d\n", pchild[4]); printf("vbase_pointer[0] : %d\n", vbase_pointer[0]); printf("vbase_pointer[1] vbase offset : %d\n", vbase_pointer[1]); for (int i=0; (Fun)vtbl[i]!=NULL; i++){ fun = (Fun)vtbl[i]; printf("vtbl[%d] : ", i); fun(); } } | ||
GrandFather ^ Father ^ Child | |||
X86 VC++ | X86 g++ | ||
打印结果 | child(0x0012FF50) : size(20) child[0] vtbl : 0x00415778 child[1] vbase_pointer : 0x004164D8 child[2] Father : 36 child[3] Child : 8 child[4] GrandFather : 60 vbase_pointer[0] : -4 vbase_pointer[1] vbase offset : 12 vtbl[0] : I am Child vtbl[1] : Father go to cutting... vtbl[2] : Child is hungry vtbl[3] : Child go to studying... | 打印结果 | |
内存布局 | Child Size : 20B |vptr| |vbase_pointer| |Father::age| |Child::age| |GrandFather::age| | 内存布局 | |
Vtbl | |Child::who()| |Father::cutting()| |Child::hungry()| |Child::studying()| | Vtbl | |
Vbase_table | |vptr offset from vbase_pointer| |vbase offset from vbase_pointer| | | |
其他 | | 其他 | |
案例二
虚基类有虚函数,但是子类没有重写该虚函数。单一虚拟继承&多态 二 | #include <stdio.h> typedef void(*Fun)(void); class GrandFather{ public: GrandFather():age(60){} virtual void fishing(){ printf("GrandFather go to fishing...\n");} int age; }; class Father : virtual public GrandFather{ public: Father():age(36){} virtual void who(){ printf("I am Father\n");} virtual void cutting(){ printf("Father go to cutting...\n");} virtual void hungry(){ printf("Father is hungry\n");} int age; }; class Child : public Father{ public: Child():age(8){} virtual void who(){ printf("I am Child\n");} virtual void studying(){ printf("Child go to studying...\n");} virtual void hungry(){ printf("Child is hungry\n");} int age; }; int main(){ Child child; Fun fun = NULL; int* pchild = (int *)&child; int* vbase_pointer = (int*)pchild[1]; int* vtbl = (int *)pchild[0]; int* vbase_vtbl = (int *)pchild[4]; printf("child(0x%p) : size(%d)\n",&child,sizeof(child)); printf("child[0] vtbl : 0x%p\n", vtbl); printf("child[1] vbase_pointer : 0x%p\n", vbase_pointer); printf("child[2] Father : %d\n", pchild[2]); printf("child[3] Child : %d\n", pchild[3]); printf("child[4] GrandFather vtbl : 0x%p\n", vbase_vtbl); printf("child[5] GrandFather : %d\n", pchild[5]); printf("vbase_pointer[0] : %d\n", vbase_pointer[0]); printf("vbase_pointer[1] vbase offset : %d\n", vbase_pointer[1]); for (int i=0; (Fun)vtbl[i]!=NULL; i++){ fun = (Fun)vtbl[i]; printf("vtbl[%d] : ", i); fun(); } for (int i=0; (Fun)vbase_vtbl[i]!=NULL; i++){ fun = (Fun)vbase_vtbl[i]; printf("vbase_vtbl[%d] : ", i); fun(); } } | ||
GrandFather ^ Father ^ Child | |||
X86 VC++ | X86 g++ | ||
打印结果 | child(0x0012FF4C) : size(24) child[0] vtbl : 0x0041577C child[1] vbase_pointer : 0x0041640C child[2] Father : 36 child[3] Child : 8 child[4] GrandFather vtbl : 0x0041594C child[5] GrandFather : 60 vbase_pointer[0] : -4 vbase_pointer[1] vbase offset : 12 vtbl[0] : I am Child vtbl[1] : Father go to cutting... vtbl[2] : Child is hungry vtbl[3] : Child go to studying... vbase_vtbl[0] : GrandFather go to fishing... | 打印结果 | |
内存布局 | Child Size : 24B |vptr| |vbase_pointer| |Father::age| |Child::age| |GrandFather::vptr| |GrandFather::age| | 内存布局 | |
Vtbl | Child vptr: |Child::who()| |Father::cutting()| |Child::hungry()| |Child::studying()| GrandFather vptr: |GrandFather::fishing()| | Vtbl | |
Vbase_table | |vptr offset from vbase_pointer| |vbase offset from vbase_pointer| | | |
其他 | | 其他 | |
[b]案例三[/b]
虚基类有虚函数,子类对该虚函数进行了重写。问题:
1. 为什么第5个字节,即vbase前面是一个NULL字节,它的作用是什么?
2. who函数应该怎么索引到?
单一虚拟继承&多态 三 | #include <stdio.h> typedef void(*Fun)(void); class GrandFather{ public: GrandFather():age(60){} virtual void who(){ printf("I am GrandFather\n");} virtual void fishing(){ printf("GrandFather go to fishing...\n");} int age; }; class Father : virtual public GrandFather{ public: Father():age(36){} virtual void who(){ printf("I am Father\n");} virtual void cutting(){ printf("Father go to cutting...\n");} virtual void hungry(){ printf("Father is hungry\n");} int age; }; class Child : public Father{ public: Child():age(8){} virtual void who(){ printf("I am Child\n");} virtual void studying(){ printf("Child go to studying...\n");} virtual void hungry(){ printf("Child is hungry\n");} int age; }; int main(){ Child child; Fun fun = NULL; int* pchild = (int *)&child; int* vbase_pointer = (int*)pchild[1]; int* vtbl = (int *)pchild[0]; int* vbase_vtbl = (int *)pchild[5]; printf("child(0x%p) : size(%d)\n",&child,sizeof(child)); printf("child[0] vtbl : 0x%p\n", vtbl); printf("child[1] vbase_pointer : 0x%p\n", vbase_pointer); printf("child[2] Father : %d\n", pchild[2]); printf("child[3] Child : %d\n", pchild[3]); printf("child[4] : %.8x\n", pchild[4]); printf("child[5] GrandFather vtbl : 0x%p\n", vbase_vtbl); printf("child[6] GrandFather : %d\n", pchild[6]); printf("vbase_pointer[0] : %d\n", vbase_pointer[0]); printf("vbase_pointer[1] vbase offset : %d\n", vbase_pointer[1]); for (int i=0; i<3; i++){ fun = (Fun)vtbl[i]; printf("vtbl[%d]: ",i); fun(); } for (int i=1; (Fun)vbase_vtbl[i]!=NULL; i++){ fun = (Fun)vbase_vtbl[i]; printf("vbase_vtbl[%d]: ", i); fun(); } } | ||
GrandFather ^ Father ^ Child | |||
X86 VC++ | X86 g++ | ||
打印结果 | child(0x0012FF48) : size(28) child[0] vtbl : 0x00416410 child[1] vbase_pointer : 0x004158BC child[2] Father : 36 child[3] Child : 8 child[4] : 00000000 child[5] GrandFather vtbl : 0x0041577C child[6] GrandFather : 60 vbase_pointer[0] : -4 vbase_pointer[1] vbase offset : 16 vtbl[0]: Father go to cutting... vtbl[1]: Child is hungry vtbl[2]: Child go to studying... vbase_vtbl[1]: GrandFather go to fishing... | 打印结果 | |
内存布局 | Child Size : 28B |vptr| |vbase_pointer| |Father::age| |Child::age| |NULL| |GrandFather::vptr| |GrandFather::age| | 内存布局 | |
Vtbl | Child vptr: |Father::cutting()| |Child::hungry()| |Child::studying()| GrandFather vptr: |GrandFather::fishing()| | Vtbl | |
Vbase_table | |vptr offset from vbase_pointer| |vbase offset from vbase_pointer| | | |
其他 | | 其他 | |
[b][b]多重虚拟继承[/b][/b]
多重虚拟继承 | #include <stdio.h> class GrandFather{ public: GrandFather():age(60){} int age; }; class Father : virtual public GrandFather{ public: Father():age(36){} int age; }; class Mother : virtual public GrandFather{ public: Mother():age(34){} int age; }; class Child : public Father, public Mother{ public: Child():age(8){} int age; }; int main(){ Child child; int* pchild = (int *)&child; int* Father_vbase_pointer = (int *)pchild[0]; int* Mother_vbase_pointer = (int *)pchild[2]; printf("child(0x%p) : size(%d)\n",&child,sizeof(child)); printf("child[0] Father_vbase_pointer : %p\n",pchild[0]); printf("child[1] Father : %d\n",pchild[1]); printf("child[2] Mother_vbase_pointer : %p\n",pchild[2]); printf("child[3] Mother : %d\n",pchild[3]); printf("child[4] Child : %d\n",pchild[4]); printf("child[5] GrandFather : %d\n",pchild[5]); printf("Father_vbase_pointer[0] : %d\n",Father_vbase_pointer[0]); printf("Father_vbase_pointer[1] vbase offset : %d\n",Father_vbase_pointer[1]); printf("Mother_vbase_pointer[0] : %d\n",Mother_vbase_pointer[0]); printf("Mother_vbase_pointer[1] vbase offset : %d\n",Mother_vbase_pointer[1]); } | ||
GrandFather ^ ^ Father Mother ^ Child | |||
X86 VC++ | X86 g++ | ||
打印结果 | child(0x0012FF4C) : size(24) child[0] Father_vbase_pointer : 00415784 child[1] Father : 36 child[2] Mother_vbase_pointer : 0041577C child[3] Mother : 34 child[4] Child : 8 child[5] GrandFather : 60 Father_vbase_pointer[0] : 0 Father_vbase_pointer[1] vbase offset : 20 Mother_vbase_pointer[0] : 0 Mother_vbase_pointer[1] vbase offset : 12 | 打印结果 | |
内存布局 | Child Size : 24B |Father_vbase_pointer| |Father::age| |Mother_vbase_pointer| |Mother::age| |Child::age| |GrandFather::age| | 内存布局 | |
Vtbl | | Vtbl | |
Vbase_table | Father Vbase table |Father vptr offset from Father_vbase_pointer | |vbase offset from Father_vbase_pointer | Mother Vbase table |Mother vptr offset from Mother_vbase_pointer | |vbase offset from Mother_vbase_pointer | | | |
其他 | | 其他 | |
多重虚拟继承&多态
案例一
虚基类无虚函数多重虚拟继承&多态 一 | #include <stdio.h> typedef void(*Fun)(void); class GrandFather{ public: GrandFather():age(60){} int age; }; class Father : virtual public GrandFather{ public: Father():age(36){} virtual void who(){ printf("I am Father\n");} virtual void cutting(){ printf("Father go to cutting...\n");} virtual void hungry(){ printf("Father is hungry\n");} int age; }; class Mother : virtual public GrandFather{ public: Mother():age(34){} virtual void who(){ printf("I am Mother\n");} virtual void sewing(){ printf("Mother go to sewing...\n");} virtual void hungry(){ printf("Mother is hungry\n");} int age; }; class Child : public Father, public Mother{ public: Child():age(8){} virtual void who(){ printf("I am Child\n");} virtual void studying(){ printf("Child go to studying...\n");} virtual void hungry(){ printf("Child is hungry\n");} int age; }; int main(){ Child child; int* pchild = (int *)&child; int* Father_vtbl = (int *)pchild[0]; int* Father_vbase_pointer = (int *)pchild[1]; int* Mother_vtbl = (int *)pchild[3]; int* Mother_vbase_pointer = (int *)pchild[4]; printf("child(0x%p) : size(%d)\n",&child,sizeof(child)); printf("child[0] Father_vtbl : %p\n",Father_vtbl); printf("child[1] Father_vbase_pointer : %p\n",Father_vbase_pointer); printf("child[2] Father : %d\n",pchild[2]); printf("child[3] Mother_vtbl : %d\n",Mother_vtbl); printf("child[4] Mother_vbase_pointer : %d\n",Mother_vbase_pointer); printf("child[5] Mother : %d\n",pchild[5]); printf("child[6] Child : %d\n",pchild[6]); printf("child[7] GrandFather : %d\n",pchild[7]); printf("Father_vbase_pointer[0] : %d\n",Father_vbase_pointer[0]); printf("Father_vbase_pointer[1] vbase offset : %d\n",Father_vbase_pointer[1]); printf("Mother_vbase_pointer[0] : %d\n",Mother_vbase_pointer[0]); printf("Mother_vbase_pointer[1] vbase offset : %d\n",Mother_vbase_pointer[1]); Fun fun = NULL; for (int i=0; i<4; i++){ fun = (Fun)Father_vtbl[i]; printf("Father_vtbl[%d] : ", i); fun(); } for (int i=0; (Fun)Mother_vtbl[i]!=NULL; i++){ fun = (Fun)Mother_vtbl[i]; printf("Mother_vtbl[%d] : ", i); fun(); } } | ||
GrandFather ^ ^ Father Mother ^ Child | |||
X86 VC++ | X86 g++ | ||
打印结果 | child(0x0012FF44) : size(32) child[0] Father_vtbl : 004168AC child[1] Father_vbase_pointer : 00416980 child[2] Father : 36 child[3] Mother_vtbl : 4286780 child[4] Mother_vbase_pointer : 4286800 child[5] Mother : 34 child[6] Child : 8 child[7] GrandFather : 60 Father_vbase_pointer[0] : -4 Father_vbase_pointer[1] vbase offset : 24 Mother_vbase_pointer[0] : -4 Mother_vbase_pointer[1] vbase offset : 12 Father_vtbl[0] : I am Child Father_vtbl[1] : Father go to cutting... Father_vtbl[2] : Child is hungry Father_vtbl[3] : Child go to studying... Mother_vtbl[0] : I am Child Mother_vtbl[1] : Mother go to sewing... Mother_vtbl[2] : Child is hungry | 打印结果 | |
内存布局 | Child Size : 32B |Father vptr| |Father_vbase_pointer| |Father::age| |Mother vptr| |Mother_vbase_pointer| |Mother::age| |Child::age| |GrandFather::age| | 内存布局 | |
Vtbl | Father vtbl |Child::who()| |Father::cutting()| |Child::hungry()| |Child::studying()| Mother vtbl |Child::who()| |Mother::sewing()| |Child::hungry()| | Vtbl | |
Vbase_table | Father Vbase table |Father vptr offset from Father_vbase_pointer | |vbase offset from Father_vbase_pointer | Mother Vbase table |Mother vptr offset from Mother_vbase_pointer | |vbase offset from Mother_vbase_pointer | | | |
其他 | Child::studying()只需要在第一个base中记录即可。 | 其他 | |
案例二
虚基类有虚函数,但是子类未重写多重虚拟继承&多态 二 | #include <stdio.h> typedef void(*Fun)(void); class GrandFather{ public: GrandFather():age(60){} virtual void fishing(){ printf("GrandFather go to fishing...\n");} int age; }; class Father : virtual public GrandFather{ public: Father():age(36){} virtual void who(){ printf("I am Father\n");} virtual void cutting(){ printf("Father go to cutting...\n");} virtual void hungry(){ printf("Father is hungry\n");} int age; }; class Mother : virtual public GrandFather{ public: Mother():age(34){} virtual void who(){ printf("I am Mother\n");} virtual void sewing(){ printf("Mother go to sewing...\n");} virtual void hungry(){ printf("Mother is hungry\n");} int age; }; class Child : public Father, public Mother{ public: Child():age(8){} virtual void who(){ printf("I am Child\n");} virtual void studying(){ printf("Child go to studying...\n");} virtual void hungry(){ printf("Child is hungry\n");} int age; }; int main(){ Child child; int* pchild = (int *)&child; int* Father_vtbl = (int *)pchild[0]; int* Father_vbase_pointer = (int *)pchild[1]; int* Mother_vtbl = (int *)pchild[3]; int* Mother_vbase_pointer = (int *)pchild[4]; int* GrandFather_vtbl = (int *)pchild[7]; printf("child(0x%p) : size(%d)\n",&child,sizeof(child)); printf("child[0] Father_vtbl : %p\n",Father_vtbl); printf("child[1] Father_vbase_pointer : %p\n",Father_vbase_pointer); printf("child[2] Father : %d\n",pchild[2]); printf("child[3] Mother_vtbl : %d\n",Mother_vtbl); printf("child[4] Mother_vbase_pointer : %d\n",Mother_vbase_pointer); printf("child[5] Mother : %d\n",pchild[5]); printf("child[6] Child : %d\n",pchild[6]); printf("child[7] GrandFather_vtbl : %d\n",GrandFather_vtbl); printf("child[8] GrandFather : %d\n",pchild[8]); printf("Father_vbase_pointer[0] : %d\n",Father_vbase_pointer[0]); printf("Father_vbase_pointer[1] vbase offset : %d\n",Father_vbase_pointer[1]); printf("Mother_vbase_pointer[0] : %d\n",Mother_vbase_pointer[0]); printf("Mother_vbase_pointer[1] vbase offset : %d\n",Mother_vbase_pointer[1]); Fun fun = NULL; for (int i=0; i<4; i++){ fun = (Fun)Father_vtbl[i]; printf("Father_vtbl[%d] : ", i); fun(); } for (int i=0; i<3; i++){ fun = (Fun)Mother_vtbl[i]; printf("Mother_vtbl[%d] : ", i); fun(); } for (int i=0; i<3; i++){ fun = (Fun)GrandFather_vtbl[i]; printf("GrandFather_vtbl[%d] : ", i); fun(); } } | ||
GrandFather ^ ^ Father Mother ^ Child | |||
X86 VC++ | X86 g++ | ||
打印结果 | child(0x0012FF40) : size(36) child[0] Father_vtbl : 00416898 child[1] Father_vbase_pointer : 00416D34 child[2] Father : 36 child[3] Mother_vtbl : 4286768 child[4] Mother_vbase_pointer : 4286740 child[5] Mother : 34 child[6] Child : 8 child[7] GrandFather_vtbl : 4286788 child[8] GrandFather : 60 Father_vbase_pointer[0] : -4 Father_vbase_pointer[1] vbase offset : 24 Mother_vbase_pointer[0] : -4 Mother_vbase_pointer[1] vbase offset : 12 Father_vtbl[0] : I am Child Father_vtbl[1] : Father go to cutting... Father_vtbl[2] : Child is hungry Father_vtbl[3] : Child go to studying... Mother_vtbl[0] : I am Child Mother_vtbl[1] : Mother go to sewing... Mother_vtbl[2] : Child is hungry GrandFather_vtbl[0] : GrandFather go to fishing... | 打印结果 | |
内存布局 | Child Size : 36B |Father vptr| |Father_vbase_pointer| |Father::age| |Mother vptr| |Mother_vbase_pointer| |Mother::age| |Child::age| |GrandFather vptr| |GrandFather::age| | 内存布局 | |
Vtbl | Father vtbl |Child::who()| |Father::cutting()| |Child::hungry()| |Child::studying()| Mother vtbl |Child::who()| |Mother::sewing()| |Child::hungry()| GrandFather vptr | GrandFather::fishing()| | Vtbl | |
Vbase_table | Father Vbase table |Father vptr offset from Father_vbase_pointer | |vbase offset from Father_vbase_pointer | Mother Vbase table |Mother vptr offset from Mother_vbase_pointer | |vbase offset from Mother_vbase_pointer | | | |
其他 | | 其他 | |
案例三
虚基类有虚函数,并且子类进行重写多重虚拟继承&多态 三 | #include <stdio.h> typedef void(*Fun)(void); class GrandFather{ public: GrandFather():age(60){} virtual void who(){ printf("I am GrandFather\n");} virtual void fishing(){ printf("GrandFather go to fishing...\n");} int age; }; class Father : virtual public GrandFather{ public: Father():age(36){} virtual void who(){ printf("I am Father\n");} virtual void cutting(){ printf("Father go to cutting...\n");} virtual void hungry(){ printf("Father is hungry\n");} int age; }; class Mother : virtual public GrandFather{ public: Mother():age(34){} virtual void who(){ printf("I am Mother\n");} virtual void sewing(){ printf("Mother go to sewing...\n");} virtual void hungry(){ printf("Mother is hungry\n");} int age; }; class Child : public Father, public Mother{ public: Child():age(8){} virtual void who(){ printf("I am Child\n");} virtual void studying(){ printf("Child go to studying...\n");} virtual void hungry(){ printf("Child is hungry\n");} int age; }; int main(){ Child child; int* pchild = (int *)&child; int* Father_vtbl = (int *)pchild[0]; int* Father_vbase_pointer = (int *)pchild[1]; int* Mother_vtbl = (int *)pchild[3]; int* Mother_vbase_pointer = (int *)pchild[4]; int* GrandFather_vtbl = (int *)pchild[8]; printf("child(0x%p) : size(%d)\n",&child,sizeof(child)); printf("child[0] Father_vtbl : %p\n",Father_vtbl); printf("child[1] Father_vbase_pointer : %p\n",Father_vbase_pointer); printf("child[2] Father : %d\n",pchild[2]); printf("child[3] Mother_vtbl : %d\n",Mother_vtbl); printf("child[4] Mother_vbase_pointer : %d\n",Mother_vbase_pointer); printf("child[5] Mother : %d\n",pchild[5]); printf("child[6] Child : %d\n",pchild[6]); printf("child[7] : %d\n",pchild[7]); printf("child[8] GrandFather_vtbl : %d\n",GrandFather_vtbl); printf("child[9] GrandFather : %d\n",pchild[9]); printf("Father_vbase_pointer[0] : %d\n",Father_vbase_pointer[0]); printf("Father_vbase_pointer[1] vbase offset : %d\n",Father_vbase_pointer[1]); printf("Mother_vbase_pointer[0] : %d\n",Mother_vbase_pointer[0]); printf("Mother_vbase_pointer[1] vbase offset : %d\n",Mother_vbase_pointer[1]); Fun fun = NULL; for (int i=0; i<3; i++){ fun = (Fun)Father_vtbl[i]; printf("Father_vtbl[%d] : ", i); fun(); } for (int i=0; i<2; i++){ fun = (Fun)Mother_vtbl[i]; printf("Mother_vtbl[%d] : ", i); fun(); } for (int i=1; i<3; i++){ fun = (Fun)GrandFather_vtbl[i]; printf("GrandFather_vtbl[%d] : ", i); fun(); } } | ||
GrandFather ^ ^ Father Mother ^ Child | |||
X86 VC++ | X86 g++ | ||
打印结果 | child(0x0012FF3C) : size(40) child[0] Father_vtbl : 004168A4 child[1] Father_vbase_pointer : 00416F00 child[2] Father : 36 child[3] Mother_vtbl : 4286616 child[4] Mother_vbase_pointer : 4287796 child[5] Mother : 34 child[6] Child : 8 child[7] : 0 child[8] GrandFather_vtbl : 4286768 child[9] GrandFather : 60 Father_vbase_pointer[0] : -4 Father_vbase_pointer[1] vbase offset : 28 Mother_vbase_pointer[0] : -4 Mother_vbase_pointer[1] vbase offset : 16 Father_vtbl[0] : Father go to cutting... Father_vtbl[1] : Child is hungry Father_vtbl[2] : Child go to studying... Mother_vtbl[0] : Mother go to sewing... Mother_vtbl[1] : Child is hungry GrandFather_vtbl[1] : GrandFather go to fishing... | 打印结果 | |
内存布局 | Child Size : 40B |Father vptr| |Father_vbase_pointer| |Father::age| |Mother vptr| |Mother_vbase_pointer| |Mother::age| |Child::age| |NULL| |GrandFather vptr| |GrandFather::age| | 内存布局 | |
Vtbl | Father vtbl |Father::cutting()| |Child::hungry()| |Child::studying()| Mother vtbl |Mother::sewing()| |Child::hungry()| GrandFather vptr | GrandFather::fishing()| | Vtbl | |
其他 | | 其他 | |
特别内存布局
同类型对象共用一个虚函数表
代码:#include <stdio.h> class Father{ public: Father():age(36){} virtual void who(){ printf("I am Father\n");} int age; }; class Child : public Father{ public: Child():age(8){} virtual void who(){ printf("I am Child\n");} int age; }; int main(){ Father father; Child child1, child2; printf("father(0x%p) child1(0x%p) child2(0x%p)\n",&father, &child1, &child2); printf("father vptr is 0x%p\n", *(int *)&father); printf("child1 vptr is 0x%p\n", *(int *)&child1); printf("child2 vptr is 0x%p\n", *(int *)&child2); }
结果:
father(0x0012FF5C) child1(0x0012FF4C) child2(0x0012FF3C)
father vptr is 0x004157B0
child1 vptr is 0x00415758
child2 vptr is 0x00415758
分析:
我们可以看到 child1和child2同属于Child类型,他们的vptr地址是一样的;而father类型是Father,它的vptr是另外一个地址。
同类型对象共用一个虚基类的指针
#include <stdio.h> class Father{ public: Father():age(36){} int age; }; class Child : virtual public Father{ public: Child():age(10){} int age; }; int main(){ Father father; Child child1, child2; printf("father Size(%d) child1 Size(%d) child2 Size(%d)\n",sizeof(father), sizeof(child1), sizeof(child2)); printf("child1 vbase_pointer is 0x%p, age is %d\n", *(int *)&child1, *((int *)&child1+1)); printf("child2 vbase_pointer is 0x%p, age is %d\n", *(int *)&child2, *((int *)&child2+1)); printf("Child object vbase offset is %d\n", *((int *)(*(int *)&child1)+1)); }
结果:
father Size(4) child1 Size(12) child2 Size(12)
child1 vbase_pointer is 0x00415768, age is 10
child2 vbase_pointer is 0x00415768, age is 10
Child object vbase offset is 8
分析:
child1和child2指向virtual base class的指针一样的,并且该指针也是指向数据段的,所以同样类型的对象的虚基类的offset是一样的。
[b]Base Class Subobject在Derived Class中有完整原样性[/b]
#include <stdio.h> class Father{ public: Father():age('f'){} virtual void who(){ printf("I am Father\n");} char age; }; class Child : public Father{ public: Child():age('c'){} virtual void who(){ printf("I am Child\n");} char age; }; int main(){ Child child; printf("child(0x%p) size(%d)\n",&child, sizeof(child)); printf("child.Father::age(0x%p)\n",&child.Father::age); printf("child.age(0x%p)\n",&child.age); }
结果:
child(0x0012FF58) size(12)
child.Father::age(0x0012FF5C)
child.age(0x0012FF60)
分析:
如果只考虑字节对齐,应该是如下布局:| vptr 4B | Father age 1B | Child age 1B | padding 2B | 共8字节
而布局实际如下:| vptr 4B | Father age 1B | padding 3B | Child age 1B | padding 3B | 共12字节
其实,这样是完全可以理解的,因为Father的对象内存布局如下:| vptr 4B | Father age 1B | padding 3B | 共8字节,那么如果将Father的对象复制到Child对象空间,那么如果按照上面第一种情况,那么Child对象的Child age数据就会被Father对象的padding数据给覆盖掉,造成了数据丢失,所以这样是不合适的。
指向virtual base Class指针
如虚拟多继承&多态案例三的内存布局Child Size : 40B
|Father vptr|
|Father_vbase_pointer|
|Father::age|
|Mother vptr|
|Mother_vbase_pointer|
|Mother::age|
|Child::age|
|NULL|
|GrandFather vptr|
|GrandFather::age|
里面有两个指向virtual base class的指针Father_vbase_pointer和Mother_vbase_pointer。
Father Vbase table
|Father vptr offsetfrom Father_vbase_pointer | -4
|vbase offset from Father_vbase_pointer| 28
Mother Vbase table
|Mother vptr offsetfrom Mother_vbase_pointer | -4
|vbase offset from Mother_vbase_pointer | 16
这样的指针有两个作用
1. 能够通过偏移找到vtbl
2. 能够通过偏移找到virtual base class subobject
相关文章推荐
- C++对象模型之详述C++对象的内存布局
- C++对象模型笔记:对象的三种内存布局
- c++对象模型 内存布局
- 深入理解C++对象模型-对象的内存布局,vptr,vtable
- 图说C++对象模型:对象内存布局详解
- C++对象模型之内存布局三(虚继承)
- C++对象模型之内存布局(1)
- 图说C++对象模型:对象内存布局详解
- C++对象模型之详述C++对象的内存布局
- c++对象内存模型【内存布局】
- C++对象模型笔记:对象实例内存布局的小小结
- 【C++对象模型】使用gcc、clang和VC++显示C++类的内存布局
- C++对象模型之简述C++对象的内存布局
- 三十二、C++内存布局,对象大小计算、虚函数虚继承对类内存模型的影响
- 图说C++对象模型:对象内存布局详解
- 深入理解C++对象模型-对象的内存布局,vptr,vtable
- 【转】图说C++对象模型:对象内存布局详解
- c++对象内存模型(内存布局)
- c++对象内存布局模型
- 图说C++对象模型:对象内存布局详解