C++ multiple inheritance virtual function memory layout

 

When debugging multiple inherited virtual functions in gdb debugging, several of them are always forgotten. Here is a summary:

Code:

 

#include <iostream>
 
using namespace std;

class Destroyable {
public:
    virtual ~Destroyable() {}
    virtual void Destroy() = 0;
};
 
class Base1 :public Destroyable{
public:
    Base1(){a=0;}
    virtual ~Base1(){cout<<"destroy base1\n";}
    virtual void f() { cout << "Base1::f" << endl; }
    virtual void g() { cout << "Base1::g" << endl; }
    virtual void h() { cout << "Base1::h" << endl; }
    void Destroy() { cout << "delete Base1\n";}

    int a;    

};
 
class Base2 {
public:
    Base2(){b= 1; c = 3;}
    virtual ~Base2(){cout<<"destroy base2\n";}
    virtual void f() { cout << "Base2::f" << endl; }
    virtual void g() { cout << "Base2::g" << endl; }
    virtual void h() { cout << "Base2::h" << endl; }

    int b;
    int c;
};

 Note: The inheritance order of Derive is 2, 1, 3.

class Base3 {
public:
    ~Base3(){cout<<"destroy base3\n";}
    virtual void f() { cout << "Base3::f" << endl; }
    virtual void g() { cout << "Base3::g" << endl; }
    virtual void h() { cout << "Base3::h" << endl; }
};
 
class Derive : public Base2, public Base1, public Base3 {
public:
    void f() { cout << "Derive::f" << endl; }
    ~Derive() {cout<<"destory derive\n";}
    virtual void g1() { cout << "Derive::g1" << endl; }
    virtual void h1() { cout << "Derive::h1" << endl; }
};
 
typedef void(*Fun)(void);
 
int main() {
    Derive d;
    Fun pFun = NULL;
    int** pVtab = (int**)&d;
 
    cout << "sizeof(b): " << sizeof(d) << endl;
 
    return 0;
}

1. The difference between gcc O1 and O0:

[root@localhost data0]# g++ test_virtual1.cpp --std=c++11 -g -O 
[root@localhost data0]# nm -an a.out | grep Destroyable 
0000000000400e76 W _ZN11DestroyableD1Ev
0000000000400e76 W _ZN11DestroyableD2Ev
0000000000400e7e W _ZN11DestroyableD0Ev
0000000000401700 V _ZTI11Destroyable
0000000000401710 V _ZTS11Destroyable
00000000004017e0 V _ZTV11Destroyable
[root@localhost data0]# g++ test_virtual1.cpp --std=c++11 -g
[root@localhost data0]# nm -an a.out | grep Destroyable 
0000000000400ccc W _ZN11DestroyableD1Ev
0000000000400ccc W _ZN11DestroyableD2Ev
0000000000400cfa W _ZN11DestroyableD0Ev
0000000000400d20 W _ZN11DestroyableC1Ev
0000000000400d20 W _ZN11DestroyableC2Ev
00000000004014e0 V _ZTV11Destroyable
00000000004015c8 V _ZTS11Destroyable
00000000004015e0 V _ZTI11Destroyable

2. View the corresponding virtual function table in multiple inheritance

[root@localhost data0]# nm -an a.out | grep Derive
0000000000401026 W _ZN6Derive1fEv
0000000000401050 W _ZThn16_N6Derive1fEv
0000000000401056 W _ZThn32_N6Derive1fEv
000000000040105c W _ZN6DeriveD1Ev
000000000040105c W _ZN6DeriveD2Ev
00000000004010dd W _ZThn16_N6DeriveD1Ev
00000000004010e6 W _ZN6DeriveD0Ev
000000000040110c W _ZThn16_N6DeriveD0Ev
0000000000401112 W _ZN6Derive2g1Ev
000000000040113c W _ZN6Derive2h1Ev
000000000040117c W _ZN6DeriveC1Ev
000000000040117c W _ZN6DeriveC2Ev
0000000000401360 V _ZTV6Derive
0000000000401508 V _ZTS6Derive
0000000000401520 V _ZTI6Derive

  

[root@localhost data0]# nm -an a.out | grep Base2
0000000000400e72 W _ZN5Base2C1Ev
0000000000400e72 W _ZN5Base2C2Ev
0000000000400e9e W _ZN5Base2D1Ev
0000000000400e9e W _ZN5Base2D2Ev
0000000000400edc W _ZN5Base2D0Ev
0000000000400f02 W _ZN5Base21fEv
0000000000400f2c W _ZN5Base21gEv
0000000000400f56 W _ZN5Base21hEv
0000000000401460 V _ZTV5Base2
0000000000401580 V _ZTS5Base2
0000000000401590 V _ZTI5Base2
(gdb) p d
$2 = {
  <Base2> = {
    _vptr.Base2 = 0x401370 <vtable for Derive+16>, 
    b = 1, 
    c = 3
  }, 
  <Base1> = {
    <Destroyable> = {
      _vptr.Destroyable = 0x4013b8 <vtable for Derive+88>
    }, 
    members of Base1: 
    a = 0
  }, 
  <Base3> = {
    _vptr.Base3 = 0x4013f8 <vtable for Derive+152>
  }, <No data fields>}
(gdb) p &d
$3 = (Derive *) 0x7fffffffe220
(gdb) x /10wx 0x7fffffffe220
0x7fffffffe220: 0x00401370      0x00000000      0x00000001      0x00000003
0x7fffffffe230: 0x004013b8      0x00000000      0x00000000      0x00000000
0x7fffffffe240: 0x004013f8      0x00000000
(gdb) x /16wx 0x00401370  -- 第一个虚函数表指针 ,以下 地址分别为虚函数表中的每个函数的地址 
0x401370 <_ZTV6Derive+16>: 0x0040105c 0x00000000 0x004010e6 0x00000000 
0x401380 <_ZTV6Derive+32>: 0x00401026 0x00000000 0x00400f2c 0x00000000 
0x401390 <_ZTV6Derive+48>: 0x00400f56 0x00000000 0x00401112 0x00000000 
0x4013a0 <_ZTV6Derive+64>: 0x0040113c 0x00000000 0xfffffff0 0xffffffff
(gdb) x 0x0040105c  
0x40105c <Derive::~Derive()>:   0xe5894855
(gdb) x 0x004010e6
0x4010e6 <Derive::~Derive()>:   0xe5894855
(gdb) x 0x00401026
0x401026 <Derive::f()>: 0xe5894855
(gdb) x 0x00400f2c
0x400f2c <Base2::g()>:  0xe5894855
(gdb) x 0x00400f56
0x400f56 <Base2::h()>:  0xe5894855
(gdb) x 0x00401112
0x401112 <Derive::g1()>:        0xe5894855
(gdb) x 0x0040113c
0x40113c <Derive::h1()>:        0xe5894855

3 View the class name to which the virtual function table belongs:   

(gdb) x /10wx 0x00401360   --0x401370 前面的8位为虚函数表所属类型的地址 即0x00401368
0x401360 <_ZTV6Derive>: 0x00000000      0x00000000      0x00401520      0x00000000
0x401370 <_ZTV6Derive+16>:      0x0040105c      0x00000000      0x004010e6      0x00000000
0x401380 <_ZTV6Derive+32>:      0x00401026      0x00000000
(gdb) x 0x00401520  -- 查看0x00401368对应的内存值即class Derive 的类型符号地址
0x401520 <_ZTI6Derive>: 0x00602290

4 Automatically change the base class address:

The main function changes the following:

int main() {
    Base1 *ptr = new Derive();
    //Derive d;
    Derive *p_d = static_cast<Derive*>(ptr);
    Fun pFun = NULL;
    int** pVtab = (int**)ptr;
    return 0;
}
(gdb) p *ptr
$1 = {
  <Destroyable> = {
    _vptr.Destroyable = 0x4013d8 <vtable for Derive+88>
  }, 
  members of Base1: 
  a = 0
}
(gdb) p *p_d
$2 = {
  <Base2> = {
    _vptr.Base2 = 0x401390 <vtable for Derive+16>, 
    b = 1, 
    c = 3
  }, 
  <Base1> = {
    <Destroyable> = {
      _vptr.Destroyable = 0x4013d8 <vtable for Derive+88>
    }, 
    members of Base1: 
    a = 0
  }, 
  <Base3> = {
    _vptr.Base3 = 0x401418 <vtable for Derive+152>
  }, <No data fields>}
(gdb) p ptr  -- 地址自动变为base1 的地址。
$3 = (Base1 *) 0x603020
(gdb) p p_d  
$4 = (Derive *) 0x603010
(gdb) x /12wx 0x603010
0x603010:       0x00401390      0x00000000      0x00000001      0x00000003
0x603020:       0x004013d8      0x00000000      0x00000000      0x00000000
0x603030:       0x00401418      0x00000000      0x00020fd1      0x00000000

Reference link:

1,https://blog.51cto.com/speakingbaicai/1686404

2,http://cn.voidcc.com/question/p-hcxhmnqe-op.html

3,https://my.oschina.net/luckysym/blog/3089906

Guess you like

Origin blog.csdn.net/zgb40302/article/details/103494112