探索多态的实现--虚表

上次说到了多态,可是多态在编译器里到底是如何实现的呢?
下面我们就来探索一下它深层的实现机制
class Base
{
public:
    virtual void func1()
    {}
    virtual void func2()
    {}
private:
    int a1;
};

void Test()
{
    Base a;
    cout << sizeof(a) << endl;//8
}   

这里写图片描述

这里为什么sizeof(a)是8呢?

因为这里还存了一个指向虚函数表的指针

我们可以从监视窗口来看一下
这里写图片描述

_vfptr就是虚函数表指针(virtual function ptr)

虚函数表(虚表):用一块连续的内存来存储虚函数的地址。

这张表解决了继承、虚函数(重写)的问题;
有虚函数就有虚表(从父类继承就自动生成了),虚函数表就像一个路标,指明了实际应该调用哪个虚函数

还是用我最喜欢的图示来说明,下图
这里写图片描述

单继承

class Base
{
public:
    virtual void func1()
    {
        cout << "Base::func1" << endl;
    }
    virtual void func2()
    {
        cout << "Base::func2" << endl;
    }
private:
    int a;
};

class Derive:public Base
{
public:
    virtual void func1()
    {
        cout << "Base::func1" << endl;
    }
    virtual void func3()
    {
        cout << "Base::func2" << endl;
    }
    virtual void func4()
    {
        cout << "Base::func2" << endl;
    }
private:
    int b;
};


void Test()
{
    Base a1;
    Derive b1;
}       

我们还是来看一下监视

这里写图片描述

这里我们可以看出子类Derive实例化出的b1,继承了父类的虚函数表指针,没有重新生成

但是这里看监视窗口是有一些问题的
这里写图片描述

并没有看到虚表里有func3、func4,这是为什么呢?难道他们没有在虚表里?
在是肯定在,只是在监视不能显示出来,所以这里我们可以自己写个函数将虚表打印出来

typedef void(*FUNC) ();
void PrintVTable(int* VTable)//打印虚表
{
    cout << "虚表地址>" << VTable << endl;

    for (int i = 0; VTable[i] != 0; ++i)
    {
        printf("第%d个虚函数地址:0x%x,->", i, VTable[i]);
        FUNC f = (FUNC)VTable[i];
        f();
    }
    cout << endl;
}
void Test()
{
    Base a1;
    Derive b1;

    int* VTable1 = (int*)(*(int*)&a1);
    int* VTable2 = (int*)(*(int*)&b1);

    PrintVTable(VTable1);
    PrintVTable(VTable2);

}   

这里写图片描述
可以看出func1在子类中重写了,func2继承来没有变动,func3、func4就在后面依次存放着

多继承

class Base1
{
public:
    virtual void func1()
    {
        cout << "Base1::func1" << endl;
    }
    virtual void func2()
    {
        cout <<" Base1::func2" << endl;
    }
private:
    int a;
};


class Base2
{
public:
    virtual void func1()
    {
        cout <<" Base2::func1" << endl;
    }
    virtual void func2()
    {
        cout << "Base2::func2 "<< endl;
    }
private:
    int b;
};

class Derive :public Base1, public Base2 //多继承,写的顺序,就是继承先后的顺序
{
public:
    virtual void func2()
    {
        cout << "Derive::func2 "<< endl;
    }
    virtual void func3()
    {
        cout <<" Derive::func3 "<< endl;
    }
private:
    int c;
};

typedef void(*FUNC) ();

void PrintfVTable(int* VTable)
{
    cout << "打印虚表>" << VTable << endl;
    for (int i = 0; VTable[i] != 0; ++i)
    {
        printf("第%d个虚函数地址:0x%x,->", i, VTable[i]);
        FUNC f = (FUNC)VTable[i];
        f();
    }
}

void Test()
{
    Derive c1;

    int* VTable = (int*)(*(int*)&c1);

    PrintfVTable(VTable);

    //Base2虚表
    VTable = (int*)(*((int*)&c1 + sizeof(Base1) / 4));
    PrintfVTable(VTable);

}

这里写图片描述

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值