深入理解虚表之非虚拟继承及虚拟继承

来源:互联网 发布:比较好的耳机 知乎 编辑:程序博客网 时间:2024/05/24 20:07

非虚拟继承

带虚函数的类

class Base{public:virtual void FunTest1(){cout<<"Base::FunTest1()"<<endl;}virtual void FunTest2(){cout<<"Base::FunTest2()"<<endl;}int _data1;};
int main(){Base b;b._data1 = 0x01;return 0;}

 

Base类没有显式定义自己的构造函数,此时编译器会和成默认的构造函数,

 

 

合成的构造函数中主要完成在对象头4个字节中填写虚表地址:

 

Base类对象最后的模型如下:

 

注意:同一个类的对象共用同一个虚表

Base b1, b2, b3;

 

从上述的结果中可以得到印证。

 

 

【单继承(派生类中没有虚函数覆盖)

class Base{public:virtual void FunTest1(){cout<<"Base::FunTest1()"<<endl;} virtual void FunTest2(){cout<<"Base::FunTest2()"<<endl;}           int _data1;};class Derive:public Base{public:virtual void FunTest3(){cout<<"Derive::FunTest3()"<<endl;}virtual void FunTest4(){cout<<"Derive::FunTest4()"<<endl;} int _data2;};//打印虚表typedef void (*VtbFun)();void PrintVtable(){cout<<"Derive类的虚函数表:"<<endl;Derive d1;d1._data1 = 0x01;d1._data2 = 0x02;int* pVTable = (int*)*(int*)&d1;VtbFun FunTest = (VtbFun)*pVTable;while(NULL != FunTest){FunTest();cout<<(int*)FunTest<<endl;pVTable += 1;FunTest = (VtbFun)*pVTable;}cout<<"虚表结束:"<<endl;}int main(){Base b1;Derive d1;return 0;}

 

按照如上分析的顺序,探索下单继承下派生类对象模型以及虚表

首先看看编译器为派生类合成的缺省构造函数:

 

 

派生类构造函数中进行了如下事情:

 

 

Derive d1;

d1._data1 = 0x01;

d1._data2 = 0x02;

派生类最后的对象模型为:

 

 

【单继承(派生类中有虚函数覆盖)

class Base{public:virtual void FunTest1(){cout<<"Base::FunTest1()"<<endl;}virtual void FunTest2(){cout<<"Base::FunTest2()"<<endl;}int _data1;};class Derive:public Base{public:virtual void FunTest1(){cout<<"Derive::FunTest1()"<<endl;}virtual void FunTest3(){cout<<"Derive::FunTest3()"<<endl;}virtual void FunTest4(){cout<<"Derive::FunTest4()"<<endl;}int _data2;};int main(){PrintVtable();return 0;}

 

派生类对象模型及虚表建议规则:

 

 

【多继承(派生类不覆盖基类虚函数)

class Base{public:virtual void FunTest1(){cout<<"Base::FunTest1()"<<endl;}virtual void FunTest2(){cout<<"Base::FunTest2()"<<endl;}int _data1;};class Base1{public:virtual void FunTest3(){cout<<"Base1::FunTest3()"<<endl;}virtual void FunTest4(){cout<<"Base1::FunTest4()"<<endl;}int _data2;};class Derive:public Base, public Base1{public:virtual void FunTest5(){cout<<"Derive::FunTest5()"<<endl;}int _data3;};int main(){cout<<"sizeof(Derive) = "<<sizeof(Derive)<<endl;Derive d;d._data1 = 0x01;d._data2 = 0x02;d._data3 = 0x03;PrintVtable();return 0;}

 

同样:看看编译器合成的派生类的对象做了什么工作

 

 

观察下派生类的对象模型和虚表的建立过程

 

 

从上面的结果可以看出,Derive类自己特有的虚函数直接添加在Base类对应虚函数表最后的位置,大家可将BaseBase1的顺序交换验证下。

 

【多继承(派生类覆盖基类虚函数)

class Base{public:virtual void FunTest1(){cout<<"Base::FunTest1()"<<endl;}virtual void FunTest2(){cout<<"Base::FunTest2()"<<endl;}int _data1;};class Base1{public:virtual void FunTest3(){cout<<"Base1::FunTest3()"<<endl;}virtual void FunTest4(){cout<<"Base1::FunTest4()"<<endl;}int _data2;};//这次将继承列表中Base和Base1的位置互换class Derive:public Base1, public Base{public:virtual void FunTest1(){cout<<"Derive::FunTest1()"<<endl;}virtual void FunTest3(){cout<<"Derive::FunTest3()"<<endl;}virtual void FunTest5(){cout<<"Derive::FunTest5()"<<endl;}int _data3;};int main(){           PrintVtable();return 0;}

 

此时派生类的对象模型和虚表的结构:

 

 

虚拟继承

//没有虚函数覆盖,但派生类有自己的虚函数

class Base{public:virtual void FunTest1(){cout<<"Base::FunTest1()"<<endl;}virtual void FunTest2(){cout<<"Base::FunTest2()"<<endl;}int _data1;};class Derive:virtual public Base{public:virtual void FunTest3(){cout<<"Derive::FunTest3()"<<endl;}virtual void FunTest4(){cout<<"Derive::FunTest4()"<<endl;}int _data2;};

 

虚拟继承编译器为派生类合成的默认构造函数分析

 

编译器为派生类合成的默认构造函数任务分析:

虚拟继承派生类对象模型分析

说明:使用环境VS2010,不同版本编译器可能会有差异

     说明:使用环境VS2010,不同版本编译器可能会有差异


1 0
原创粉丝点击