• C++ 虚函数和多重继承的内存布局初探


    C++ 对象的内存布局

    一切以事实说话:

    代码:

       1: #include <stdio.h> 
       2:  
       3: class A {
       4:   public:   
       5:     int a;
       6:     int b;  
       7:     int c;  
       8: };
       9:  
      10: int main(int argc, char** argv) {
      11:   A obj;
      12:   printf(" obj   :%p
     obj.a: %p 
     obj.b: %p 
     obj.c: %p
    " ,                                                          
      13:         &obj, &obj.a, &obj.b, &obj.c);
      14:   return 0;
      15: }

    执行结果:

    image

    不同的机器执行的结果可能不同,但是从这里的出的一个结论是:

    对象的地址是整个类的起始地址(也就是低地址)。其成员的地址顺序和其在类中声明的顺序有关系。

    而对上面的代码稍加修改,增加一个虚函数。

       1: #include <stdio.h>
       2:  
       3: class A { 
       4:   public:
       5:     virtual void show() {}                                                                                               
       6:     int a;
       7:     int b;
       8:     int c;
       9: };
      10:  
      11: int main(int argc, char** argv) {
      12:   A obj;
      13:   printf(" obj   :%p
     obj.a: %p 
     obj.b: %p 
     obj.c: %p
    " ,
      14:         &obj, &obj.a, &obj.b, &obj.c);
      15:   return 0;
      16: }

    测试结果:

    image

    这里是由于增加了一个虚函数表的指针(测试机器为64位系统,故指针为8个字节)。从这里可以看出,虚函数表指针在类的起始地址,这也是为了对于不同的类该地址的偏移相同。

       1: class X {
       2: };
       3: class Y {
       4:   public:
       5:     virtual void f() {};
       6: };
       7: class X1 : public virtual X {
       8: };
       9: class X2 : public virtual X {
      10: };
      11: class A1 : public X1, public X2 {
      12: };
      13: class X3 : public X {
      14: };
      15: class X4 : public X {
      16: };
      17: class A2 : public X3, public X4 {
      18: };
      19: class Y1 : public virtual Y {
      20: };
      21: class Y2 : public virtual Y {
      22: };
      23: class B1 : public Y1, public Y2 {
      24: };
      25: class Y3 : public Y {
      26: };
      27: class Y4 : public Y {
      28: };
      29: class B2 : public Y3, public Y4 {
      30: };
      31:  
      32: int main (int argc, char** argv) {
      33:   printf("sizeof(X) %lu
    ", sizeof(X));
      34:   printf("sizeof(Y) %lu
    ", sizeof(Y));
      35:   printf("sizeof(X1) %lu
    ", sizeof(X1));
      36:   printf("sizeof(X2) %lu
    ", sizeof(X2));
      37:   printf("sizeof(A1) %lu
    ", sizeof(A1));
      38:   printf("sizeof(X3) %lu
    ", sizeof(X3));
      39:   printf("sizeof(X4) %lu
    ", sizeof(X4));
      40:   printf("sizeof(A2) %lu
    ", sizeof(A2));
      41:   printf("sizeof(Y1) %lu
    ", sizeof(Y1));
      42:   printf("sizeof(Y2) %lu
    ", sizeof(Y2));
      43:   printf("sizeof(B1) %lu
    ", sizeof(B1));
      44:   printf("sizeof(Y3) %lu
    ", sizeof(Y3));
      45:   printf("sizeof(Y4) %lu
    ", sizeof(Y4));
      46:   printf("sizeof(B2) %lu
    ", sizeof(B2));
      47:   return 0;
      48: }        

    执行结果:

    image

    上面的测试结果得出的结论:

    1. 空类的大小不是0,而是1,这样是提供一个占位符,这样由空类创建出的两个对象的地址就会不同,以作区分。
    2. 当类不是空的时候,该占位符就不需要了,类的大小就是类中成员所需的空间大小

    注: 本想深入一探究竟,不过这部分和编译器有很大的关系,非朝夕可以搞定。先写这么多,再多做了解后再补充吧。

    refer:

    http://blog.csdn.net/haoel/article/details/3081328

    http://blog.csdn.net/haoel/article/details/3081385

    http://blog.chinaunix.net/uid-22535463-id-2749544.html

  • 相关阅读:
    OpenWrt VTun Client
    LibreSpeed install on centos
    信号频道带宽、符号率、速率对应关系
    DVB相关标准
    Cisco Switch STP
    TROUBLESHOOTING MULTICAST ROUTING
    企业ERP核心模型与云计算生态
    Istio介绍(1)
    ServiceMesh案例
    Jenkins流水线发布实现CICD到Kubernetes
  • 原文地址:https://www.cnblogs.com/lovemdx/p/3335094.html
Copyright © 2020-2023  润新知