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