虚表剖析

虚表剖析
举例:

   class Test
{
public:
Test()
{
    _test = 10;
    cout << "this = " << this << endl;
};
virtual ~Test()
{}
private:
int _test;
};

    int main()
{
Test t;
cout << sizeof(Test) << endl;
system("pause");
return 0;
};

这里写图片描述
当有虚函数时,编译器会生成一张虚表,在对象的前四个字节(虚表指针);
当有多个虚函数时,函数模型又是怎样呢?
上代码验证(没有重写):
在基类和派生类中分别添加虚函数

class CBase
{
public:
CBase(){m_iTest = 10;}
virtual void FunTest0(){cout<<"CBase::FunTest0()";}
virtual void FunTest1(){cout<<"CBase::FunTest1()";}
virtual void FunTest2(){cout<<"CBase::FunTest2()";}
private:
int m_iTest;
};
class CDerived:public CBase
{
public:
virtual void FunTest4() {cout<<"CDerived::FunTest4()";}
    virtual void FunTest5(){cout<<"CDerived::FunTest5()";}
virtual void FunTest6(){cout<<"CDerived::FunTest6()";}
};
typedef void (*FUN_TEST)();
void FunTest()
{
CBase base;
cout<< "CBase vfptr:"<<endl;
for (int iIdx = 0; iIdx < 3; ++iIdx)
{
FUN_TEST funTest = (FUN_TEST)(*((int*)*(int *)&base + iIdx));
funTest();
cout<< ": "<<(int *)funTest<<endl;
    }
cout<<endl;
CDerived derived;
cout<< "CDerived vfptr:"<<endl;
for (int iIdx = 0; iIdx < 6; ++iIdx)
{
    FUN_TEST funTest = (FUN_TEST)(*((int*)*(int *)&derived + iIdx));
funTest();
cout<< ": "<<(int *)funTest<<endl;
}
}

运行结果:
Alt text

结论:
1.虚函数按照声明顺序存放在虚表中,
2.在派生类中,先是基类的虚函数,后存放派生类的虚函数,

有重写

class CBase
{
public:
virtual void FunTest0(){cout<<"CBase::FunTest0()"<<endl;}
virtual void FunTest1(){cout<<"CBase::FunTest1()"<<endl;}
virtual void FunTest2(){cout<<"CBase::FunTest2()"<<endl;}
virtual void FunTest3(){cout<<"CBase::FunTest3()"<<endl;}
};
class CDerived:public CBase
    {
public:
virtual void FunTest0(){cout<<"CDerived::FunTest0()" <<endl;}
virtual void FunTest1(){cout<<"CDerived::FunTest1()" <<endl;}
virtual void FunTest4(){cout<<"CDerived::FunTest4()" <<endl;}
virtual void FunTest5(){cout<<"CDerived::FunTest5()" <<endl;}
};

这里写图片描述

1.在派生类中,先拷贝基类的虚函数表,如果重写了某个虚函数,就在对应位置换成重写后的虚函数,
2.接着跟上自己定义的虚函数,

ATTENTION:

CBase base;
CDerived derived;
pBase = &base;//指向基类,得到的是基类的虚表指针
pBase->FunTest();
pBase = &derived;//指向派生类,得到派生类的指针
pBase->FunTest();

CDerived* ptr = (CDerived*)&base;//派生类的指针指向基类地址
ptr->FunTest();

通过基类的引用或指针调用虚函数时,要根据运行时指向的类型决定;
调用非虚函数时,无论基类指向何种类型,调用的都是基类的函数,

通过一个派生类类型的指针强制指向基类地址,调用非虚函数时是派生类的函数,调用虚函数时是调用基类中的。

多重继承:
上代码:

class CBase0
{
public:
CBase0(){m_iTest = 0xB0;}
virtual void PrintB0(){cout<<"m_iTest = "<<hex<<m_iTest<< " CBase0::PrintB0()" <<endl;}
int m_iTest;
};
class CBase1
{
public:
CBase1(){m_iTest = 0xB1;}
virtual void PrintB1(){cout<<"m_iTest = "<<hex<<m_iTest<< " CBase1::PrintB1()" <<endl;}
int m_iTest;
};
class CBase2
{
public:
CBase2(){m_iTest = 0xB2;}
virtual void PrintB2(){cout<<"m_iTest = "<<hex<<m_iTest<< " CBase2::PrintB2()" <<endl;}
int m_iTest;
};
class CDerived:public CBase0, public CBase1, public CBase2
{
public:
CDerived(){m_iTest = 0xD0;}
virtual void PrintD(){cout<<"m_iTest = "<<hex<<m_iTest<< " CDerived::PrintD()"<<endl;}
int m_iTest;
};

数据模型:
这里写图片描述

CDerived 的虚函数表放在第一个继承基类的虚表后面;

当有虚函数覆盖时,每次调用的都是派生类中重写的;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值