虚函数底层机制探究

  1. virtual关键字标识虚函数。
  2. 在C++中,使用基类的引用或指针调用一个虚函数是,发生动态绑定(或称运行时绑定)。

目录

1.对象内部成员验证

结论一:对象内部存放的是nonstatic 数据成员。

2.虚表指针验证

结论二:vptr(虚表指针)的初始化是由构造函数完成的。

结论三:vptr(虚表指针)是nonstatic 数据成员。

3.对虚函数存放位置验证。

结论四:虚函数表中存放的是函数指针(指向虚函数)。


1、对象内部成员验证

根据C++对象模型的描述,nonstatic 数据成员存放在对象的内部。static 数据成员、nonstatic和static函数成员存放在对象的外部。

测试代码一:

#include <iostream>
using namespace std;
class Base
{
public:
    static int getGlobal(); //static 函数成员

    void setData(const int data); //nonstatic函数成员
    int getDate()const;           //nonstatic 函数成员
private:
    static int g_global; //static 数据成员
    int m_data;          //nonstatic 数据成员
};
int Base::g_global = 0;
int main()
{
    Base bs; //定义一个对象
    bs.setData(12);
    int Base_size = sizeof(bs);//查看对象(bs)占用内存大小
    return 0;
}

调试结果:

图一

 

分析:

图1调试结果可以看出,对象(bs)的内存占用大小只包含了nonstatic 数据成员(m_data)。

结论一:对象内部存放的是nonstatic 数据成员。

 

2.虚表指针验证

虚函数的实现有2部分构成:

  1).每个产生一堆虚函数的指针,存放在虚函数表中(virtual table, vtbl)

  2).每个对象有一个指向vtbl的指针(vptr)。vptr的设置和重置由每个类的构造函数,析构函数和拷贝赋值运算符自动完成。

测试代码二:

class Base
{
public:
    static int getGlobal();

    virtual void show(); //虚函数
    
    void setData(const int data);
    int getDate()const;
private:
    static int g_global;
    int m_data;
};
//==============================================
main.c:
int main()
{
    1: Base bs;
    2: bs.setData(12);
    3: int Base_size = sizeof(bs);
    return 0;
}

调试结果:

图2-1各变量初始状态
图2-2 第一条指令执行后状态

 

单步调试发现:当执行1指令后,虚表指针内容发生改变。

结论二:vptr(虚表指针)的初始化是由构造函数完成的。

图2-3 2、3指令执行结束后各变量状态

分析:图2-3显示 对象(bs)内存大小为8。测试代码相较测试一,多了一个虚函数(void show())。对应的调试结果中多了_vptr.Base变量。根据结论一推出,_vptr.Base是一个nonstatic 数据成员。

结论三:vptr(虚表指针)是nonstatic 数据成员。

 

3.对虚函数存放位置验证。

测试代码三:

class Base
{
public:
    static int getGlobal();

    virtual void show();
    virtual void show1();

    void setData(const int data);
    int getDate()const;
private:
    static int g_global;
    int m_data;
};
//================================================================
int main()
{
    Base bs;
    bs.setData(12);
    bs.show();
    void (Base::*p1)() = &Base::show;  //定义函数指针(p1),获取虚函数(show)地址
    void (Base::*p2)() = &Base::show1; //定义函数指针(p2), 获取虚函数(show1)地址
    int Base_size = sizeof(bs);
    return 0;
}

调试显示:

图3-1 p1、p2显示了虚函数的地址

 

分析:从调试结果看,函数指针获取的地址是,虚函数在virtual table(虚函数表) 中的偏移位置。并且大小为4字节,所以推出结论4.

结论四:虚函数表中存放的是函数指针(指向虚函数)。

图3-2 虚函数机制结构图

相关参考资料:

[1] C++语言知识点汇总

[2] 何为C++对象模型?

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值