• c++内存对象模型--vs2017下的分析,32位


    1、没有虚继承,没有虚函数的情况:

    class VB
    {
    public:
        int m_a;
        //virtual void print() {
        //    cout << "VB" << endl;
        //}
    };
    class Base : public VB
    {
    public:
        int m_b1;
        //virtual void pb()
        //{
        //    cout << "pb" << endl;
        //}
    };
    
    class Base2 : public VB
    {
    public:
        int m_b2;
        //virtual void pb2()
        //{
        //    cout << "pb2" << endl;
        //}
    };
    
    class Derive : public Base, public Base2
    {
    public:
        int m_d;
        //virtual void pb()
        //{
        //    cout << "Derive pb" << endl;
        //}
        //virtual void pb2()
        //{
        //    cout << "Derive pb2" << endl;
        //}
    };
    View Code

    vs里得到的内存对象:

     1 1>class VB    size(4):
     2 1>    +---
     3 1> 0    | m_a
     4 1>    +---
     5 1>
     6 1>class Base    size(8):
     7 1>    +---
     8 1> 0    | +--- (base class VB)
     9 1> 0    | | m_a
    10 1>    | +---
    11 1> 4    | m_b1
    12 1>    +---
    13 1>
    14 1>class Base2    size(8):
    15 1>    +---
    16 1> 0    | +--- (base class VB)
    17 1> 0    | | m_a
    18 1>    | +---
    19 1> 4    | m_b2
    20 1>    +---
    21 1>
    22 1>class Derive    size(20):
    23 1>    +---
    24 1> 0    | +--- (base class Base)
    25 1> 0    | | +--- (base class VB)
    26 1> 0    | | | m_a
    27 1>    | | +---
    28 1> 4    | | m_b1
    29 1>    | +---
    30 1> 8    | +--- (base class Base2)
    31 1> 8    | | +--- (base class VB)
    32 1> 8    | | | m_a
    33 1>    | | +---
    34 1>12    | | m_b2
    35 1>    | +---
    36 1>16    | m_d
    37 1>    +---
    38 1>

    从上面信息可以得知:

      1)、继承在对象内的布局是按继承的从左到右顺序,依次放到派生类对象内的;

      2)、可以看到VB在Derive里面有两份(虚继承就是为了解决这个问题);

      3)派生类对象的指针转换为基类指针,只需要进行偏移即可。

    2、有虚函数的情况:

    class VB
    {
    public:
        int m_a;
        virtual void print() {
            cout << "VB" << endl;
        }
    };
    class Base : public VB
    {
    public:
        int m_b1;
        virtual void pb()
        {
            cout << "pb" << endl;
        }
    };
    
    class Base2 : public VB
    {
    public:
        int m_b2;
        virtual void pb2()
        {
            cout << "pb2" << endl;
        }
    };
    
    class Derive : public Base, public Base2
    {
    public:
        int m_d;
        virtual void pb()
        {
            cout << "Derive pb" << endl;
        }
        virtual void pb2()
        {
            cout << "Derive pb2" << endl;
        }
    };
    View Code

    vs里得到的内存对象:

     1 1>class VB    size(8):
     2 1>    +---
     3 1> 0    | {vfptr}
     4 1> 4    | m_a
     5 1>    +---
     6 1>
     7 1>VB::$vftable@:
     8 1>    | &VB_meta
     9 1>    |  0
    10 1> 0    | &VB::print
    11 1>
    12 1>VB::print this adjustor: 0
    13 1>
    14 1>class Base    size(12):
    15 1>    +---
    16 1> 0    | +--- (base class VB)
    17 1> 0    | | {vfptr}
    18 1> 4    | | m_a
    19 1>    | +---
    20 1> 8    | m_b1
    21 1>    +---
    22 1>
    23 1>Base::$vftable@:
    24 1>    | &Base_meta
    25 1>    |  0
    26 1> 0    | &VB::print
    27 1> 1    | &Base::pb
    28 1>
    29 1>Base::pb this adjustor: 0
    30 1>
    31 1>class Base2    size(12):
    32 1>    +---
    33 1> 0    | +--- (base class VB)
    34 1> 0    | | {vfptr}
    35 1> 4    | | m_a
    36 1>    | +---
    37 1> 8    | m_b2
    38 1>    +---
    39 1>
    40 1>Base2::$vftable@:
    41 1>    | &Base2_meta
    42 1>    |  0
    43 1> 0    | &VB::print
    44 1> 1    | &Base2::pb2
    45 1>
    46 1>Base2::pb2 this adjustor: 0
    47 1>
    48 1>class Derive    size(28):
    49 1>    +---
    50 1> 0    | +--- (base class Base)
    51 1> 0    | | +--- (base class VB)
    52 1> 0    | | | {vfptr}
    53 1> 4    | | | m_a
    54 1>    | | +---
    55 1> 8    | | m_b1
    56 1>    | +---
    57 1>12    | +--- (base class Base2)
    58 1>12    | | +--- (base class VB)
    59 1>12    | | | {vfptr}
    60 1>16    | | | m_a
    61 1>    | | +---
    62 1>20    | | m_b2
    63 1>    | +---
    64 1>24    | m_d
    65 1>    +---
    66 1>
    67 1>Derive::$vftable@Base@:
    68 1>    | &Derive_meta
    69 1>    |  0
    70 1> 0    | &VB::print
    71 1> 1    | &Derive::pb
    72 1>
    73 1>Derive::$vftable@Base2@:
    74 1>    | -12
    75 1> 0    | &VB::print
    76 1> 1    | &Derive::pb2
    77 1>
    78 1>Derive::pb this adjustor: 0
    79 1>Derive::pb2 this adjustor: 12
    80 1>

    从上面信息可以得知:

      1)VB的大小为8,其中一个虚函数指针,一个int成员变量;

      2)Derive的大小为28,其中一个Base(12Byte),一个Base(12Byte),一个自己的成员变量int m_d,一共28Byte;

      3)我们知道,对象的虚函数指针指向虚表,虚表里存着函数指针,那么具体是怎么实现的多态呢?

        从Base来看:继承了VB,虚函数指针在对象的第0个地址;

        从Derive来看:由于继承顺序,所以Base类放在的第一个位置,对应的虚函数指针也按Base里的顺序放置的;

        再根据表Derive::$vftable@Base@ 和 Derive::$vftable@Base@,可以得知:在Derive里的,虚函数表的第二项已经被替换为&Derive::pb了,也就是被覆盖了;在调用pb函数时,根据虚函数表指针 + 表里的偏移,得到的就是派生类里的pb函数了;这里需要注意的是:虚函数表指针是怎么被赋值的,从反汇编我们可以知道,在构造函数里,会将虚函数表指针赋值。

    Derive::Derive()构造函数的反汇编代码:

     1 00C12450  push        ebp  
     2 00C12451  mov         ebp,esp  
     3 00C12453  sub         esp,0CCh  
     4 00C12459  push        ebx  
     5 00C1245A  push        esi  
     6 00C1245B  push        edi  
     7 00C1245C  push        ecx  
     8 00C1245D  lea         edi,[ebp-0CCh]  
     9 00C12463  mov         ecx,33h  
    10 00C12468  mov         eax,0CCCCCCCCh  
    11 00C1246D  rep stos    dword ptr es:[edi]  
    12 00C1246F  pop         ecx  
    13 00C12470  mov         dword ptr [this],ecx  
    14 00C12473  mov         ecx,dword ptr [this]  
    15 00C12476  call        Base::Base (0C1150Ah)  
    16 00C1247B  mov         ecx,dword ptr [this]  
    17 00C1247E  add         ecx,0Ch  
    18 00C12481  call        Base2::Base2 (0C114FBh)  
    19 00C12486  mov         eax,dword ptr [this]  
    20 00C12489  mov         dword ptr [eax],offset Derive::`vftable' (0C1AC28h)  //这个是对象的第0个位置,放置了虚函数表的地址
    21 00C1248F  mov         eax,dword ptr [this]  
    22 00C12492  mov         dword ptr [eax+0Ch],offset Derive::`vftable' (0C1AD54h)  //这个偏移刚好是第二个虚函数表指针的地址
    23 00C12499  mov         eax,dword ptr [this]  
    24 00C1249C  pop         edi  
    25 00C1249D  pop         esi  
    26 00C1249E  pop         ebx  
    27 00C1249F  add         esp,0CCh  
    28 00C124A5  cmp         ebp,esp  
    29 00C124A7  call        __RTC_CheckEsp (0C11316h)  
    30 00C124AC  mov         esp,ebp  
    31 00C124AE  pop         ebp  
    32 00C124AF  ret 

    3、有虚继承的时候:

     1 class VB
     2 {
     3 public:
     4     int m_a;
     5     virtual void print() {
     6         cout << "VB" << endl;
     7     }
     8 };
     9 class Base : virtual public VB
    10 {
    11 public:
    12     int m_b1;
    13     virtual void pb()
    14     {
    15         cout << "pb" << endl;
    16     }
    17 };
    18 
    19 class Base2 : virtual public VB
    20 {
    21 public:
    22     int m_b2;
    23     virtual void pb2()
    24     {
    25         cout << "pb2" << endl;
    26     }
    27 };
    28 
    29 class Derive : public Base, public Base2
    30 {
    31 public:
    32     int m_d;
    33     virtual void pb()
    34     {
    35         cout << "Derive pb" << endl;
    36     }
    37     virtual void pb2()
    38     {
    39         cout << "Derive pb2" << endl;
    40     }
    41 };
    View Code

    vs里得到的对象信息:

      1 1>class VB    size(8):    //没有变化
      2 1>    +---
      3 1> 0    | {vfptr}
      4 1> 4    | m_a
      5 1>    +---
      6 1>
      7 1>VB::$vftable@:
      8 1>    | &VB_meta
      9 1>    |  0
     10 1> 0    | &VB::print
     11 1>
     12 1>VB::print this adjustor: 0
     13 1>
     14 1>class Base    size(20):    //多了一个虚基类表指针
     15 1>    +---
     16 1> 0    | {vfptr}        //虚函数表指针,size 4
     17 1> 4    | {vbptr}        //虚基类表指针,size 4
     18 1> 8    | m_b1          //size 4
     19 1>    +---
     20 1>    +--- (virtual base VB)  //大小没变化,就是布局上,被放到Base成员变量的后面了,如果有Base: virtual public vb0, virtual public vb1呢,这个虚继承的顺序将是在Base末端依次布局的顺序(见后面的补充)
     21 1>12    | {vfptr}
     22 1>16    | m_a
     23 1>    +---
     24 1>
     25 1>Base::$vftable@Base@:
     26 1>    | &Base_meta
     27 1>    |  0
     28 1> 0    | &Base::pb
     29 1>
     30 1>Base::$vbtable@:
     31 1> 0    | -4
     32 1> 1    | 8 (Based(Base+4)VB)
     33 1>
     34 1>Base::$vftable@VB@:
     35 1>    | -12
     36 1> 0    | &VB::print
     37 1>
     38 1>Base::pb this adjustor: 0
     39 1>vbi:       class  offset o.vbptr  o.vbte fVtorDisp
     40 1>              VB      12       4       4 0
     41 1>
     42 1>class Base2    size(20):
     43 1>    +---
     44 1> 0    | {vfptr}
     45 1> 4    | {vbptr}
     46 1> 8    | m_b2
     47 1>    +---
     48 1>    +--- (virtual base VB)
     49 1>12    | {vfptr}
     50 1>16    | m_a
     51 1>    +---
     52 1>
     53 1>Base2::$vftable@Base2@:
     54 1>    | &Base2_meta
     55 1>    |  0
     56 1> 0    | &Base2::pb2
     57 1>
     58 1>Base2::$vbtable@:
     59 1> 0    | -4
     60 1> 1    | 8 (Base2d(Base2+4)VB)
     61 1>
     62 1>Base2::$vftable@VB@:
     63 1>    | -12
     64 1> 0    | &VB::print
     65 1>
     66 1>Base2::pb2 this adjustor: 0
     67 1>vbi:       class  offset o.vbptr  o.vbte fVtorDisp
     68 1>              VB      12       4       4 0
     69 1>
     70 1>class Derive    size(36):
     71 1>    +---
     72 1> 0    | +--- (base class Base)//size 12,末端的虚继承信息被共享了,虚基类表指针也是在构造函数里赋值的
     73 1> 0    | | {vfptr}
     74 1> 4    | | {vbptr}
     75 1> 8    | | m_b1
     76 1>    | +---
     77 1>12    | +--- (base class Base2)
     78 1>12    | | {vfptr}
     79 1>16    | | {vbptr}
     80 1>20    | | m_b2
     81 1>    | +---
     82 1>24    | m_d
     83 1>    +---
     84 1>    +--- (virtual base VB)
     85 1>28    | {vfptr}
     86 1>32    | m_a
     87 1>    +---
     88 1>
     89 1>Derive::$vftable@Base@:
     90 1>    | &Derive_meta
     91 1>    |  0
     92 1> 0    | &Derive::pb
     93 1>
     94 1>Derive::$vftable@Base2@:
     95 1>    | -12
     96 1> 0    | &Derive::pb2
     97 1>
     98 1>Derive::$vbtable@Base@:
     99 1> 0    | -4
    100 1> 1    | 24 (Derived(Base+4)VB)
    101 1>
    102 1>Derive::$vbtable@Base2@:
    103 1> 0    | -4
    104 1> 1    | 12 (Derived(Base2+4)VB)
    105 1>
    106 1>Derive::$vftable@VB@:
    107 1>    | -28
    108 1> 0    | &VB::print
    109 1>
    110 1>Derive::pb this adjustor: 0
    111 1>Derive::pb2 this adjustor: 12
    112 1>vbi:       class  offset o.vbptr  o.vbte fVtorDisp
    113 1>              VB      28       4       4 0
    114 1>

    Derive::Derive的反汇编:

     1 00BB24E0  push        ebp  
     2 00BB24E1  mov         ebp,esp  
     3 00BB24E3  sub         esp,0CCh  
     4 00BB24E9  push        ebx  
     5 00BB24EA  push        esi  
     6 00BB24EB  push        edi  
     7 00BB24EC  push        ecx  
     8 00BB24ED  lea         edi,[ebp-0CCh]  
     9 00BB24F3  mov         ecx,33h  
    10 00BB24F8  mov         eax,0CCCCCCCCh  
    11 00BB24FD  rep stos    dword ptr es:[edi]  
    12 00BB24FF  pop         ecx  
    13 00BB2500  mov         dword ptr [this],ecx  
    14 00BB2503  cmp         dword ptr [ebp+8],0  
    15 00BB2507  je          Derive::Derive+48h (0BB2528h)  //这里有个判断
    16 00BB2509  mov         eax,dword ptr [this]  
    17 00BB250C  mov         dword ptr [eax+4],offset Derive::`vbtable' (0BBAC8Ch)  //Derive::$vbtable@Base@:
    18 00BB2513  mov         eax,dword ptr [this]  
    19 00BB2516  mov         dword ptr [eax+10h],offset Derive::`vbtable' (0BBAC98h)  //Derive::$vbtable@Base2@:
    20 00BB251D  mov         ecx,dword ptr [this]  
    21 00BB2520  add         ecx,1Ch  
    22 00BB2523  call        VB::VB (0BB1267h)  //基类的构造函数
    23 00BB2528  push        0  
    24 00BB252A  mov         ecx,dword ptr [this]  
    25 00BB252D  call        Base::Base (0BB1334h)  //基类的构造函数
    26 00BB2532  push        0  
    27 00BB2534  mov         ecx,dword ptr [this]  
    28 00BB2537  add         ecx,0Ch  
    29 00BB253A  call        Base2::Base2 (0BB1244h)  //基类的构造函数
    30 00BB253F  mov         eax,dword ptr [this]  
    31 00BB2542  mov         dword ptr [eax],offset Derive::`vftable' (0BBAC74h)  //虚函数表的设置则是基类构造函数call之后
    32 00BB2548  mov         eax,dword ptr [this]  
    33 00BB254B  mov         dword ptr [eax+0Ch],offset Derive::`vftable' (0BBAC50h)  
    34 00BB2552  mov         eax,dword ptr [this]  
    35 00BB2555  mov         ecx,dword ptr [eax+4]  
    36 00BB2558  mov         edx,dword ptr [ecx+4]  
    37 00BB255B  mov         eax,dword ptr [this]  
    38 00BB255E  mov         dword ptr [eax+edx+4],offset Derive::`vftable' (0BBAC84h)  //从布局可以看到,一共有三个虚函数表指针,这是共享的那个VB的虚函数表指针的偏移
    39 00BB2566  mov         eax,dword ptr [this]  
    40 00BB2569  pop         edi  
    41 00BB256A  pop         esi  
    42 00BB256B  pop         ebx  
    43 00BB256C  add         esp,0CCh  
    44 00BB2572  cmp         ebp,esp  
    45 00BB2574  call        __RTC_CheckEsp (0BB1325h)  
    46 00BB2579  mov         esp,ebp  
    47 00BB257B  pop         ebp  
    48 00BB257C  ret         4  

    从上面汇编分析得知,虚基类表的指针,最终指向;虚函数表指针在构造函数后赋值,最终指向派生类的虚函数表指针。

    4、下面考虑如何将派生类指针转为基类指针?

      1)没有虚函数 + 没有虚继承情况下,指针偏移即可;

      2)有虚函数 + 没有虚继承,指针偏移即可,刚好虚函数指针在每个类型的第0个位置,多态执行函数很方便,可以使用dynamic_cast动态转换;

      3)没有虚函数 + 虚继承,是否可以用dynamic_cast运行期转换:不可以;

      4)有虚继承的情况,我们看下面的转换:

     1     Derive* d = new Derive();
     2 00132D78  push        24h  
     3 00132D7A  call        operator new (0131401h)  
     4 00132D7F  add         esp,4  
     5 00132D82  mov         dword ptr [ebp-11Ch],eax  
     6 00132D88  cmp         dword ptr [ebp-11Ch],0  
     7 00132D8F  je          fun2+78h (0132DC8h)  
     8 00132D91  xor         eax,eax  
     9 00132D93  mov         ecx,dword ptr [ebp-11Ch]  
    10 00132D99  mov         dword ptr [ecx],eax  
    11 00132D9B  mov         dword ptr [ecx+4],eax  
    12 00132D9E  mov         dword ptr [ecx+8],eax  
    13 00132DA1  mov         dword ptr [ecx+0Ch],eax  
    14 00132DA4  mov         dword ptr [ecx+10h],eax  
    15 00132DA7  mov         dword ptr [ecx+14h],eax  
    16 00132DAA  mov         dword ptr [ecx+18h],eax  
    17 00132DAD  mov         dword ptr [ecx+1Ch],eax  
    18 00132DB0  mov         dword ptr [ecx+20h],eax  
    19 00132DB3  push        1  
    20 00132DB5  mov         ecx,dword ptr [ebp-11Ch]  
    21 00132DBB  call        Derive::Derive (0131078h)  
    22 00132DC0  mov         dword ptr [ebp-124h],eax  
    23 00132DC6  jmp         fun2+82h (0132DD2h)  
    24 00132DC8  mov         dword ptr [ebp-124h],0  
    25 00132DD2  mov         edx,dword ptr [ebp-124h]  
    26 00132DD8  mov         dword ptr [d],edx  
    27     Base* b = d;
    28 00132DDB  mov         eax,dword ptr [d]  //从内存布局中,我们知道Base是第一个位置的,所以直接把地址给b
    29 00132DDE  mov         dword ptr [b],eax  
    30     Base2* b2 = d;
    31 00132DE1  cmp         dword ptr [d],0  
    32 00132DE5  je          fun2+0A5h (0132DF5h)  
    33 00132DE7  mov         eax,dword ptr [d]  
    34 00132DEA  add         eax,0Ch              //Base2在Derive中的偏移是12
    35 00132DED  mov         dword ptr [ebp-124h],eax  
    36 00132DF3  jmp         fun2+0AFh (0132DFFh)  
    37 00132DF5  mov         dword ptr [ebp-124h],0  
    38 00132DFF  mov         ecx,dword ptr [ebp-124h]  
    39 00132E05  mov         dword ptr [b2],ecx  
    40     VB* vb = d;
    41 00132E08  cmp         dword ptr [d],0  
    42 00132E0C  jne         fun2+0CAh (0132E1Ah)  
    43 00132E0E  mov         dword ptr [ebp-124h],0  
    44 00132E18  jmp         fun2+0E0h (0132E30h)  
    45 00132E1A  mov         eax,dword ptr [d]  
    46 00132E1D  mov         ecx,dword ptr [eax+4]  //虚基类表指针,Derive::$vbtable@Base@
    47 00132E20  mov         edx,dword ptr [ecx+4]  //得到偏移,24
    48 00132E23  mov         eax,dword ptr [d]  
    49 00132E26  lea         ecx,[eax+edx+4]      //this + 偏移24 + 4 =this+28,刚好等于VB在Derive中的对象内存位置
    50 00132E2A  mov         dword ptr [ebp-124h],ecx  
    51 00132E30  mov         edx,dword ptr [ebp-124h]  
    52 00132E36  mov         dword ptr [vb],edx  
    53     VB*vb1 = b;
    54 00132E39  cmp         dword ptr [b],0  
    55 00132E3D  jne         fun2+0FBh (0132E4Bh)  
    56 00132E3F  mov         dword ptr [ebp-124h],0  
    57 00132E49  jmp         fun2+111h (0132E61h)  
    58 00132E4B  mov         eax,dword ptr [b]  
    59 00132E4E  mov         ecx,dword ptr [eax+4]  
    60 00132E51  mov         edx,dword ptr [ecx+4]  
    61 00132E54  mov         eax,dword ptr [b]  
    62 00132E57  lea         ecx,[eax+edx+4]  
    63 00132E5B  mov         dword ptr [ebp-124h],ecx  
    64 00132E61  mov         edx,dword ptr [ebp-124h]  
    65 00132E67  mov         dword ptr [vb1],edx  
    66     VB*vb2 = b2;
    67 00132E6A  cmp         dword ptr [b2],0  
    68 00132E6E  jne         fun2+12Ch (0132E7Ch)  
    69 00132E70  mov         dword ptr [ebp-124h],0  
    70     VB*vb2 = b2;
    71 00132E7A  jmp         fun2+142h (0132E92h)  
    72 00132E7C  mov         eax,dword ptr [b2]  
    73 00132E7F  mov         ecx,dword ptr [eax+4]  
    74 00132E82  mov         edx,dword ptr [ecx+4]  
    75 00132E85  mov         eax,dword ptr [b2]  
    76 00132E88  lea         ecx,[eax+edx+4]  
    77 00132E8C  mov         dword ptr [ebp-124h],ecx  
    78 00132E92  mov         edx,dword ptr [ebp-124h]  
    79 00132E98  mov         dword ptr [vb2],edx  

    5、多个虚继承下的内存对象信息:

     1 class VB
     2 {
     3 public:
     4     int m_a;
     5     virtual void print() {
     6         cout << "VB" << endl;
     7     }
     8 };
     9 class VB2
    10 {
    11 public:
    12     int m_a2;
    13     virtual void print2() {
    14         cout << "VB" << endl;
    15     }
    16 };
    17 class Base : virtual public VB,virtual public VB2
    18 {
    19 public:
    20     int m_b1;
    21     virtual void pb()
    22     {
    23         cout << "pb" << endl;
    24     }
    25 };
    View Code
     1 1>class VB    size(8):
     2 1>    +---
     3 1> 0    | {vfptr}
     4 1> 4    | m_a
     5 1>    +---
     6 1>
     7 1>VB::$vftable@:
     8 1>    | &VB_meta
     9 1>    |  0
    10 1> 0    | &VB::print
    11 1>
    12 1>VB::print this adjustor: 0
    13 1>
    14 1>class VB2    size(8):
    15 1>    +---
    16 1> 0    | {vfptr}
    17 1> 4    | m_a2
    18 1>    +---
    19 1>
    20 1>VB2::$vftable@:
    21 1>    | &VB2_meta
    22 1>    |  0
    23 1> 0    | &VB2::print2
    24 1>
    25 1>VB2::print2 this adjustor: 0
    26 1>
    27 1>class Base    size(28):
    28 1>    +---
    29 1> 0    | {vfptr}
    30 1> 4    | {vbptr}
    31 1> 8    | m_b1
    32 1>    +---
    33 1>    +--- (virtual base VB)
    34 1>12    | {vfptr}
    35 1>16    | m_a
    36 1>    +---
    37 1>    +--- (virtual base VB2)
    38 1>20    | {vfptr}
    39 1>24    | m_a2
    40 1>    +---
    41 1>
    42 1>Base::$vftable@Base@:
    43 1>    | &Base_meta
    44 1>    |  0
    45 1> 0    | &Base::pb
    46 1>
    47 1>Base::$vbtable@:
    48 1> 0    | -4
    49 1> 1    | 8 (Based(Base+4)VB)
    50 1> 2    | 16 (Based(Base+4)VB2)
    51 1>
    52 1>Base::$vftable@VB@:
    53 1>    | -12
    54 1> 0    | &VB::print
    55 1>
    56 1>Base::$vftable@VB2@:
    57 1>    | -20
    58 1> 0    | &VB2::print2
    59 1>
    60 1>Base::pb this adjustor: 0
    61 1>vbi:       class  offset o.vbptr  o.vbte fVtorDisp
    62 1>              VB      12       4       4 0
    63 1>             VB2      20       4       8 0
    64 1>
    View Code

    可以看到Base里只有一个虚基类表指针,且指向的内容是:

    1>Base::$vbtable@:
    1> 0 | -4
    1> 1 | 8 (Based(Base+4)VB)
    1> 2 | 16 (Based(Base+4)VB2)

  • 相关阅读:
    【随笔】野生在左 科班在右——数据结构学习誓师贴
    javascript基础修炼(7)——Promise,异步,可靠性
    express中间件系统的基本实现
    javascript基础修炼(6)——前端路由的基本原理
    javascript基础修炼(5)—Event Loop(Node.js)
    一统江湖的大前端(7)React.js-从开发者到工程师
    一统江湖的大前端(6)commander.js + inquirer.js——懒,才是第一生产力
    一统江湖的大前端(5)editorconfig + eslint——你的代码里藏着你的优雅
    Jmeter接口测试之用户自定义变量(九)
    Jmeter4.0接口测试之案例实战(七)
  • 原文地址:https://www.cnblogs.com/mingbujian/p/13984419.html
Copyright © 2020-2023  润新知