派生类对象模型之单继承关系中的虚表剖析

我们都知道C++中利用虚函数实现动态多态,而这里多态的实现又于虚表(要与虚继承中的偏移量表区分开)有关,因此,在这里我探讨一下简单含虚函数的单继承关系中派生类对象模型与虚表问题。
首先给出如下继承关系:

class Base
{
public:
    Base()
        : b(1)
    {}
    virtual void Print()
    {
        std::cout << "Base::Print()" << std::endl;
    }
    int b;
};
class Derive : public Base
{
public:
    Derive()
        : d(2)
    {}
    virtual void Print()
    {
        std::cout << "Derive::Print()" << std::endl;
    }
    int d;
};

在两个类中都声明了函数名相同的虚函数,但是虚函数函数体的输出不同,先来看基类Base的对象地址空间中的数据存放:
这里写图片描述
根据基类对象的内存空间数据分布,我们可以很容易地画出一个拥有虚函数的类的对象模型
这里写图片描述
值得注意的是,我们都知道在一个类中成员函数不存放在类对象中的,而拥有虚函数的类的每个对象都有一个虚表,那么这些虚表是相同的还是相互独立的呢?现在创建两个Base类对象,观察两个对象的虚表:
这里写图片描述
因此,我们可以画出一个拥有虚函数的类的多个对象的空间分布
这里写图片描述

在前面的代码中,基类Base和派生类Derive中都有虚函数成员,因此如果两者没有继承关系的话他们都应该是上面这种模型。而这里派生类公有继承自基类,如果按照之前分析的无虚函数成员的继承关系中派生类的对象模型,可以猜测:这里的派生类Derive应该有两个虚表,低地址处存放着继承自基类的虚表地址,高地址处存放着派生类自己的虚表地址,那么究竟是不是这样的呢?我们来观察:
这里写图片描述
可以看到,在派生类对象地址空间中仅在低地址处存放着一个虚表地址,按照上面的猜测这应该是继承自基类的虚表地址,那么派生类自己的虚表地址在哪里呢?我们先进入这里的虚表中观察:
这里写图片描述
可以看到,虚表只存放着派生类的虚函数,那么基类的虚函数在哪里呢?
别急,我们先在基类中增加一个派生类中没有的虚函数:

class Base
{
public:
    Base()
        : b(1)
    {}
    virtual void Print()
    {
        std::cout << "Base::Print()" << std::endl;
    }
    virtual void Get()
    {
        std::cout << "Get()" << std::endl;
    }
    int b;
};

然后同时观察基类派生类的虚表:
这里写图片描述
我们可以看到,当基类中存在派生类中没有声明的虚函数时,派生类的虚表中也会存在这个虚函数,而如果派生类中声明的虚函数与基类中虚函数相同时,虚表中就仅存在派生类中声明的虚函数。
虚表机理:派生类的虚表继承自基类,在初始时虚表中存在所有基类拥有的虚函数,当派生类中存在与虚表中虚函数的函数原型完全一样的虚函数时,派生类的虚函数就会在相应位置对原来的虚函数进行覆盖,而派生类中原有的虚函数则继续存在,派生类中新增的虚函数则按声明顺序放在虚表表尾,即这样的:
这里写图片描述

分析完毕,不足之处望高手斧正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值