虚函数指针 虚函数表

虚函数指针和虚函数表

1.虚函数的含义

只有用virtual声明类的成员函数,称之为虚函数。

2.虚函数的作用

就是一句话:实现多态的基石

实现多态的三大步:

1.存在继承关系 子类继承父类

2.子类重写父类的virtual function

3.子类以父类的指针或者是引用的身份出现

3.虚函数的实现原理 多态的实现原理

相信很多人都能说出来其中实现关键原理,就是两点:虚函数表指针(vptr),虚函数表(vftable)

1 虚函数指针在哪? 干什么用的?
2 什么是虚函数表? 表-》信息 虚函数表-》什么信息的? 有什么用?

3 A 类  a 对象    b c 成员  a对象内存布局是什么样? 
gdb一个普通类 内存布局  
一个类里面如果有了虚函数 内存布局?
一个类继承一个类  内存布局是什么样子?
一个类继承并且重写虚函数  内存布局是什么样 虚函数表发生什么变化呢?
  • 普通类

我们首先来看下没有虚函数的情况下 一个普通的类的实例对象在内存中的分布

demo.cpp

#include
using namespace std;
class Base{
    public:
            Base():m_base(0),m_base1(' '){};
            void test() const  { cout<<"Base print()"<

在终端输入如下命令

g++ demo.cpp -g
gdb ./a.out
(gdb) list
(gdb) b 14
(gdb) p b
$1 = {m_base = 0, m_base1 = 32 ' '}

可以看到对象b的内存布局是由成员数据构成。

  • 当类中存在虚函数

test.cpp

#include
using namespace std;
class Base{
public:
    Base():m_base(0),m_base1(' '){}
    virtual void print() const  { cout<<"Base print()"<

在终端输入如下命令

g++ test.cpp -g
gdb ./a.out

gdb过程如下:

[echoqian@cvm-10_4_1_62 virtual]$ gdb a.out 
(gdb) list
4	public:
5	    Base():m_base(0),m_base1(' '){}
6	    virtual void print() const  { cout<<"Base print()"<, m_base = 0, m_base1 = 32 ' '}

此时我们可以看到对象的布局中多了一个虚函数。并且这个虚函数位于这个对象的开头

我们可以打印出虚函数表

(gdb) info vtbl b
vtable for 'Base' @ 0x400a60 (subobject @ 0x7fffffffe420):
[0]: 0x400986 

此时虚函数表中有一个函数地址。虚函数表中就存放了这个函数的地址。

  • 子类继承父类不重写虚函数

test.cpp

#include
using namespace std;
class Base{
public:
    Base():m_base(0),m_base1(' '){}
    virtual void print() const  { cout<<"Base print()"<

gdb过程如下:

[echoqian@cvm-10_4_1_62 virtual]$ g++ -g test.cpp 
[echoqian@cvm-10_4_1_62 virtual]$ gdb test.cpp 
(gdb) list
(gdb) b 21
(gdb) r
(gdb) p b
$1 = {_vptr.Base = 0x400b10 <vtable for Base+16>, m_base = 0, m_base1 = 32 ' '}
(gdb) p d
$2 = {<Base> = {_vptr.Base = 0x400af0 <vtable for Derive+16>, m_base = 0, m_base1 = 32 ' '}, m_dirive = 4196928}
(gdb) p &d.m_base
$3 = (int *) 0x7fffffffe408
(gdb) p &d.m_base1
$4 = 0x7fffffffe40c " "
(gdb) p &d.m_dirive
$5 = (int *) 0x7fffffffe410
(gdb) quit
  • 子类继承父类重写虚函数
    test.cpp
#include
using namespace std;
class Base{
public:
    Base():m_base(0),m_base1(' '){}
    virtual void print() const  { cout<<"Base print()"<

gdb过程如下:

[echoqian@cvm-10_4_1_62 virtual]$ g++ -g test1.cpp 
[echoqian@cvm-10_4_1_62 virtual]$ gdb ./a.out 
(gdb) list
(gdb) b 22
Breakpoint 1 at 0x400960: file test1.cpp, line 22.
(gdb) r
(gdb) p b
$1 = {_vptr.Base = 0x400b40 <vtable for Base+16>, m_base = 0, m_base1 = 32 ' '}
(gdb) p d
$2 = {<Base> = {_vptr.Base = 0x400b20 <vtable for Derive+16>, m_base = 0, m_base1 = 32 ' '}, <No data fields>}
(gdb) info vtbl b
vtable for 'Base' @ 0x400b40 (subobject @ 0x7fffffffe420):
[0]: 0x4009e2 <Base::print() const>
(gdb) info vtbl d
vtable for 'Derive' @ 0x400b20 (subobject @ 0x7fffffffe410):
[0]: 0x400a0c <Derive::print() const>

对比图:
虚函数指针 虚函数表_第1张图片

1.虚函数表指针

1.什么是虚函数表指针,他在哪里,有什么用?

我们把对象从首地址开始的4个字节或者是8个字节,这个位置我们称之为虚函数表指针(vptr),它里面包含一个地址指向的就是虚函数表(vftable)的地址。

2.虚函数表

1.什么是虚函数表,他又在哪里,有什么用?

虚函数表说白了就是里面是一组地址的数组(就是函数指针数组),他所在的位置就是虚函数表指针里面所存储的地址,它里面所包含的地址就是我们重写了父类的虚函数的地址(没有重写父类的虚函数那么默认的就是父类的函数地址)。

你可能感兴趣的:(C/C++语言)