您的位置:首页 > 编程语言 > C语言/C++

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

2013-03-03 21:44 483 查看
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

 

其他

 

其他

 

[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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: