读书人

C++ - 对象模型之 内存储器布局

发布时间: 2013-03-06 16:20:31 作者: rapoo

C++ - 对象模型之 内存布局

C++对象模型目录

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

其他

其他



单一继承&多态

单一继承&多态

#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进行记录。

其他



单一虚拟继承

单一虚拟继承

#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来得到的

其他


单一虚拟继承&多态案例一虚基类无虚函数。

单一虚拟继承&多态 一

#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|

其他

其他


案例三虚基类有虚函数,子类对该虚函数进行了重写。问题: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|

其他

其他



多重虚拟继承

多重虚拟继承

#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('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. 能够通过偏移找到vtbl2. 能够通过偏移找到virtual base class subobject

读书人网 >C++

热点推荐