#include <iostream>
using namespace std;
class Point2D {
public:
Point2D(int _x, int _y): x(_x), y(_y) {}
virtual void print() const {
cout << x << "," << y << endl;
}
virtual ~Point2D() {}
protected:
int x, y;
};
class Point3D: public Point2D {
public:
Point3D(int _x, int _y, int _z): Point2D(_x, _y), z(_z) {}
void print() const {
cout << x << "," << y << "," << z << endl;
}
private:
int z;
};
int main() {
Point2D *p2d = new Point3D(1, 2, 3);
p2d->print();
Point2D *p2d2 = new Point2D(1, 2);
p2d2->print();
return 0;
}
基类Point2D
中有虚函数print
和需析构函数
基类指针p2d
指向了派生类对象,用gdb调试
(gdb) print p2d
$1 = (Point2D *) 0x555555768e70
(gdb) x/20x 0x555555768e70
0x555555768e70: 0x55755d10 0x00005555 0x00000001 0x00000002
0x555555768e80: 0x00000003 0x00000000 0x0000f181 0x00000000
查看基类指针,前8个字节是虚表指针,然后是4字节的x
,4字节的y
,4字节的z
查看虚函数表指针
(gdb) x/20x 0x555555755d10
0x555555755d10 <_ZTV7Point3D+16>: 0x55554d88 0x00005555 0x55554e08 0x00005555
0x555555755d20 <_ZTV7Point3D+32>: 0x55554e32 0x00005555 0x00000000 0x00000000
对应3个虚函数地址,分别查看对应哪个虚函数
第一个是Point3D
的print
虚函数
(gdb) x/20x 0x555555554d88
0x555555554d88 <Point3D::print() const>: 0xe5894855 0x10ec8348 0xf87d8948 0xf8458b48
0x555555554d98 <Point3D::print() const+16>: 0x8908408b 0x3d8d48c6 0x0020127c 0xfffcb7e8
0x555555554da8 <Point3D::print() const+32>: 0x358d48ff 0x00000135 0xe8c78948 0xfffffc58
0x555555554db8 <Point3D::print() const+48>: 0x48c28948 0x8bf8458b 0xc6890c40 0xe8d78948
0x555555554dc8 <Point3D::print() const+64>: 0xfffffc94 0x12358d48 0x48000001 0x35e8c789
第二个是Point3D
的虚析构函数
(gdb) x/20x 0x555555554e08
0x555555554e08 <Point3D::~Point3D()>: 0xe5894855 0x10ec8348 0xf87d8948 0xf5158d48
0x555555554e18 <Point3D::~Point3D()+16>: 0x4800200e 0x48f8458b 0x8b481089 0x8948f845
0x555555554e28 <Point3D::~Point3D()+32>: 0xfed0e8c7 0xc990ffff 0x485590c3 0x8348e589
第三个是合成的Point3D
的析构函数
(gdb) x/20x 0x555555554e32
0x555555554e32 <Point3D::~Point3D()>: 0xe5894855 0x10ec8348 0xf87d8948 0xf8458b48
0x555555554e42 <Point3D::~Point3D()+16>: 0xe8c78948 0xffffffbe 0xf8458b48 0x000018be
0x555555554e52 <Point3D::~Point3D()+32>: 0xc7894800 0xfffbd5e8 0x0fc3c9ff 0x5741001f
可以反汇编看看这个析构函数
(gdb) disassemble 0x555555554e32
Dump of assembler code for function Point3D::~Point3D():
0x0000555555554e32 <+0>: push %rbp
0x0000555555554e33 <+1>: mov %rsp,%rbp
0x0000555555554e36 <+4>: sub $0x10,%rsp
0x0000555555554e3a <+8>: mov %rdi,-0x8(%rbp)
0x0000555555554e3e <+12>: mov -0x8(%rbp),%rax
0x0000555555554e42 <+16>: mov %rax,%rdi
0x0000555555554e45 <+19>: callq 0x555555554e08 <Point3D::~Point3D()>
0x0000555555554e4a <+24>: mov -0x8(%rbp),%rax
0x0000555555554e4e <+28>: mov $0x18,%esi
0x0000555555554e53 <+33>: mov %rax,%rdi
0x0000555555554e56 <+36>: callq 0x555555554a30 <_ZdlPvm@plt>
0x0000555555554e5b <+41>: leaveq
0x0000555555554e5c <+42>: retq
End of assembler dump.
可以看到调用了地址为0x555555554e08
的第二个析构函数
再看看基类指针p2d2
,指向了Point2D
对象
(gdb) n
1,2,3
28 Point2D *p2d2 = new Point2D(1, 2);
(gdb) n
29 p2d2->print();
(gdb) print p2d2
$2 = (Point2D *) 0x5555557692a0
(gdb) x/20x 0x5555557692a0
0x5555557692a0: 0x55755d38 0x00005555 0x00000001 0x00000002
0x5555557692b0: 0x00000000 0x00000000 0x0000ed51 0x00000000
前面8个字节是虚函数表指针,然后是4字节的x
和4字节的y
查看虚函数表指针
(gdb) x/20x 0x555555755d38
0x555555755d38 <_ZTV7Point2D+16>: 0x55554ca2 0x00005555 0x55554cfe 0x00005555
0x555555755d48 <_ZTV7Point2D+32>: 0x55554d18 0x00005555 0xf7dc5438 0x00007fff
同样是3个指针
第一个是print
虚函数
(gdb) x/20x 0x555555554ca2
0x555555554ca2 <Point2D::print() const>: 0xe5894855 0x10ec8348 0xf87d8948 0xf8458b48
0x555555554cb2 <Point2D::print() const+16>: 0x8908408b 0x3d8d48c6 0x00201362 0xfffd9de8
0x555555554cc2 <Point2D::print() const+32>: 0x358d48ff 0x0000021b 0xe8c78948 0xfffffd3e
0x555555554cd2 <Point2D::print() const+48>: 0x48c28948 0x8bf8458b 0xc6890c40 0xe8d78948
0x555555554ce2 <Point2D::print() const+64>: 0xfffffd7a 0x48c28948 0x12e0058b 0x89480020
第二个是Point2D
的虚析构函数
(gdb) x/20x 0x555555554cfe
0x555555554cfe <Point2D::~Point2D()>: 0xe5894855 0xf87d8948 0x2b158d48 0x48002010
0x555555554d0e <Point2D::~Point2D()+16>: 0x48f8458b 0x5d901089 0x485590c3 0x8348e589
第三个也是Point2D
的虚析构函数
(gdb) x/20x 0x555555554d18
0x555555554d18 <Point2D::~Point2D()>: 0xe5894855 0x10ec8348 0xf87d8948 0xf8458b48
0x555555554d28 <Point2D::~Point2D()+16>: 0xe8c78948 0xffffffce 0xf8458b48 0x000010be
0x555555554d38 <Point2D::~Point2D()+32>: 0xc7894800 0xfffcefe8 0x90c3c9ff 0xe5894855
反汇编看看
(gdb) disassemble 0x555555554d18
Dump of assembler code for function Point2D::~Point2D():
0x0000555555554d18 <+0>: push %rbp
0x0000555555554d19 <+1>: mov %rsp,%rbp
0x0000555555554d1c <+4>: sub $0x10,%rsp
0x0000555555554d20 <+8>: mov %rdi,-0x8(%rbp)
0x0000555555554d24 <+12>: mov -0x8(%rbp),%rax
0x0000555555554d28 <+16>: mov %rax,%rdi
0x0000555555554d2b <+19>: callq 0x555555554cfe <Point2D::~Point2D()>
0x0000555555554d30 <+24>: mov -0x8(%rbp),%rax
0x0000555555554d34 <+28>: mov $0x10,%esi
0x0000555555554d39 <+33>: mov %rax,%rdi
0x0000555555554d3c <+36>: callq 0x555555554a30 <_ZdlPvm@plt>
0x0000555555554d41 <+41>: leaveq
0x0000555555554d42 <+42>: retq
End of assembler dump.
也是调用了0x555555554cfe
的第二个析构函数