虚函数表

单继承的虚函数表研究
这里写图片描述

#include<iostream>
using namespace std;
//单继承虚函数研究
class Base
{
private:
    int _b;
public:
    virtual void FunTest1()
    {
        cout << "Base::FunTeat1()" << endl;
    }
    virtual void FunTest2()
    {
        cout << "Base::FunTeat2()" << endl;
    }
};
class Dir:public Base
{
private:
    int _d;
public:
    virtual void FunTest1()
    {
        cout << "Dir::FunTest1()" << endl;
    }
    virtual void FunTest3()
    {
        cout << "Dir::FunTest3()" << endl;
    }
};
typedef void(*VFP)();//VFP是一个函数指针,可以指向一个无参,无返回值的函数
void Find_VFT(Base& b, char ch[])
{
    VFP * p=(VFP*)(*(int*)(&b));

    while (*p)
    {
        (*p)();
        p++;
    }
}
int main(void)
{
    Base b;
    Dir d;
    cout << sizeof(b) << endl;
    cout << sizeof(d) << endl;
    Find_VFT(b, "Base VFT");
    printf("\n");
    printf("\n");
    Find_VFT(d, "Dir VFT");
    printf("\n");

    return 0;
}

/*

结论:
1,对于单继承方式,子类对象先将父类对象的虚函数表继承下来。(注意是另开辟空间存放虚表,由子类和父类虚表地址不同可以看出)
2,当子类中存在对父类中的虚函数进行重写的话,虚表中,被重写的虚函数由新的函数代替(只替换子类的,父类的没有变)
3,虚表中函数的顺序严格按照定义时的顺序存放。可以打印中看出这一点。
4,虚表地址在类的模型中前4个字节中存放,我们拿到该数据的方法(*(int*))(&对象名),但是这样拿出来的是一个整形数据,我们还要对这个数据强转,类型为父类对象第一个虚函数同样的指针(因为虚表中第一个地址为父类第一个虚函数地址),强转后,对该函数指针调用,将调用到虚表中的第一个虚函数。如例程序中的函数原型为 void Find_VFT(Base & b,char ch[]).
5.当我们定义的虚函数不是一样的(返回值类型,参数列表)时,在用指针调用时,要做对应的强转,不然可能调用出错。
6,虚表最后有4个字节的0000 0000做结束标志。

*/

多继承虚函数研究
这里写图片描述

#include<iostream>
using namespace std;
#if 1
//多继承虚函数研究
class Base1
{
private:
    int _b1;
public:
    virtual void FunTest1()
    {
        cout << "Base1::FunTeat1()" << endl;
    }
    virtual void FunTest2()
    {
        cout << "Base1::FunTeat2()" << endl;
    }
};

class Base2
{
private:
    int _b2;
public:
    virtual void FunTest3()
    {
        cout << "Base2::FunTeat3()" << endl;
    }
    virtual void FunTest4()
    {
        cout << "Base2::FunTeat4()" << endl;
    }
    virtual void FunTest5()
    {
        cout << "Base2::FunTeat5()" << endl;
    }
};

class Dir :public Base1,public Base2
{
private:
    int _d;
public:
    virtual void FunTest1()
    {
        cout << "Dir::FunTest1()" << endl;
    }
    virtual void FunTest3()
    {
        cout << "Dir::FunTest3()" << endl;
    }
    virtual void FunTest6()
    {
        cout << "Dir::FunTest6()" << endl;
    }

};


typedef void(*VFP)();//VFP是一个函数指针,可以指向一个无参,无返回值的函数
void Find_VFT(Base1& b, char ch[])
{
    VFP * p = (VFP*)(*(int*)(&b));

    while (*p)
    {
        (*p)();
        p++;
    }
}
void Find_VFT(Base2& b, char ch[])
{
    VFP * p = (VFP*)(*(int*)(&b));

    while (*p)
    {
        (*p)();
        p++;
    }
}
int main(void)
{
    Base1 b1;
    Base2 b2;
    Dir d;
    cout << sizeof(b1) << endl;
    cout << sizeof(b2) << endl;
    cout << sizeof(d) << endl;
    Base1& db1 = d;
    Base2& db2 = d;
    Find_VFT(db1, "Base1_VFT:");
    printf("\n");
    printf("\n");
    Find_VFT(db2, "Base1_VFT:");
    printf("\n");
    printf("\n");

    return 0;
}
/*
结论:
1,多继承中虚函数表要维持多个。
2,单继承中的结论这里同样可以用。
3,如果子类中有单独的虚函数,则该虚函数的地址放在继承的第一个父类虚函数表中。且放在其所有虚函数的地址之后,顺序同样满足定义时的顺序存放。
*/
#endif
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值