【虚函数指针 虚函数表】

虚函数指针和虚函数表

1.虚函数的含义

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

2.虚函数的作用

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

  1. 存在继承关系 子类继承父类
  2. 子类重写父类的virtual function
  3. 子类以父类的指针或者是引用的身份出现

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

虚函数表指针(vptr),虚函数表(vftable)

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

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

普通类

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

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

    protected:
            int m_base; 
            char m_base1;   
};
int main(){
        Base b;
        return 0;
}

在终端输入如下命令

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<iostream>
using namespace std;
class Base{
public:
    Base():m_base(0),m_base1(' '){}
    virtual void print() const  { cout<<"Base print()"<<endl; }

protected:
    int m_base;	
    char m_base1;	
};
int main(){
    Base b;
    return 0;
}

在终端输入如下命令

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()"<<endl; }
7	
8	protected:
9	    int m_base;	
10	    char m_base1;	
11	};
12	int main(){
13	    Base b;
(gdb) b 14
Breakpoint 1 at 0x400904: file test.cpp, line 14.
(gdb) r
(gdb) p b
$1 = {_vptr.Base = 0x400a60 <vtable for Base+16>, m_base = 0, m_base1 = 32 ' '}

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

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

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

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

test.cpp

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

protected:
    int m_base;	
    char m_base1;	
};

class Derive: public Base{
    private:
    int m_dirive;
};

int main(){
    Base b;
    Derive d;
    return 0;
}

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<iostream>
using namespace std;
class Base{
public:
    Base():m_base(0),m_base1(' '){}
    virtual void print() const  { cout<<"Base print()"<<endl; }

protected:
    int m_base;	
    char m_base1;	
};

class Derive: public Base{
public: 
    void print() const  { cout<<"Derive print()"<<endl; }

};

int main(){
    Base b;
    Derive d;
    return 0;
}

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.什么是虚函数表指针,他在哪里,有什么用?
我们把对象从首地址开始的4个字节或者是8个字节,这个位置我们称之为虚函数表指针(vptr),它里面包含一个地址指向的就是虚函数表(vftable)的地址。

2.虚函数表

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

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值