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]);

         /*通过pchildpFather获得偏移量都可以获得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(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是一样的。


Base Class Subobject在Derived Class中有完整原样性

#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

你可能感兴趣的