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

来源:互联网 发布:松下机器人示教编程 编辑:程序博客网 时间:2024/05/22 13:28

http://blog.csdn.net/yc2zgh1314/article/details/51166375

非虚拟继承

带虚函数的类

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
  1. class Base  
  2. {  
  3. public:  
  4. virtual void FunTest1()  
  5. {  
  6. cout<<"Base::FunTest1()"<<endl;  
  7. }  
  8. virtual void FunTest2()  
  9. {  
  10. cout<<"Base::FunTest2()"<<endl;  
  11. }  
  12. int _data1;  
  13. };  
[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
  1. int main()  
  2. {  
  3. Base b;  
  4. b._data1 = 0x01;  
  5. return 0;  
  6. }  

 

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

 

 

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

 

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

 

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

Base b1, b2, b3;

 

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

 

 

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

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
  1. class Base  
  2.   
  3. {  
  4. public:  
  5. virtual void FunTest1()  
  6. {cout<<"Base::FunTest1()"<<endl;}   
  7. virtual void FunTest2()  
  8. {cout<<"Base::FunTest2()"<<endl;}  
  9.            int _data1;  
  10. };  
  11.   
  12. class Derive:public Base  
  13. {  
  14. public:  
  15. virtual void FunTest3()  
  16. {cout<<"Derive::FunTest3()"<<endl;}  
  17. virtual void FunTest4()  
  18. {cout<<"Derive::FunTest4()"<<endl;}  
  19.  int _data2;  
  20. };  
  21.   
  22. //打印虚表  
  23.   
  24. typedef void (*VtbFun)();  
  25. void PrintVtable()  
  26. {  
  27. cout<<"Derive类的虚函数表:"<<endl;  
  28. Derive d1;  
  29. d1._data1 = 0x01;  
  30. d1._data2 = 0x02;  
  31. int* pVTable = (int*)*(int*)&d1;  
  32. VtbFun FunTest = (VtbFun)*pVTable;  
  33. while(NULL != FunTest)  
  34. {  
  35. FunTest();  
  36. cout<<(int*)FunTest<<endl;  
  37. pVTable += 1;  
  38. FunTest = (VtbFun)*pVTable;  
  39. }  
  40. cout<<"虚表结束:"<<endl;  
  41. }  
  42.   
  43. int main()  
  44. {  
  45. Base b1;  
  46. Derive d1;  
  47. return 0;  
  48. }  

 

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

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

 

 

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

 

 

Derive d1;

d1._data1 = 0x01;

d1._data2 = 0x02;

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

 

 

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

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
  1. class Base  
  2.   
  3. {  
  4. public:  
  5. virtual void FunTest1()  
  6. {  
  7. cout<<"Base::FunTest1()"<<endl;  
  8. }  
  9. virtual void FunTest2()  
  10. {  
  11. cout<<"Base::FunTest2()"<<endl;  
  12. }  
  13. int _data1;  
  14. };  
  15.   
  16. class Derive:public Base  
  17. {  
  18. public:  
  19. virtual void FunTest1()  
  20. {  
  21. cout<<"Derive::FunTest1()"<<endl;  
  22. }  
  23. virtual void FunTest3()  
  24. {  
  25. cout<<"Derive::FunTest3()"<<endl;  
  26. }  
  27. virtual void FunTest4()  
  28. {  
  29. cout<<"Derive::FunTest4()"<<endl;  
  30. }  
  31. int _data2;  
  32. };  
  33.   
  34. int main()  
  35. {  
  36. PrintVtable();  
  37. return 0;  
  38. }  

 

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

 

 

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

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
  1. class Base  
  2.   
  3. {  
  4. public:  
  5. virtual void FunTest1()  
  6. {  
  7. cout<<"Base::FunTest1()"<<endl;  
  8. }  
  9. virtual void FunTest2()  
  10. {  
  11. cout<<"Base::FunTest2()"<<endl;  
  12. }  
  13. int _data1;  
  14. };  
  15.   
  16. class Base1  
  17. {  
  18. public:  
  19.   
  20. virtual void FunTest3()  
  21. {  
  22. cout<<"Base1::FunTest3()"<<endl;  
  23. }  
  24. virtual void FunTest4()  
  25. {  
  26. cout<<"Base1::FunTest4()"<<endl;  
  27. }  
  28. int _data2;  
  29. };  
  30.   
  31. class Derive:public Base, public Base1  
  32. {  
  33. public:  
  34. virtual void FunTest5()  
  35. {  
  36. cout<<"Derive::FunTest5()"<<endl;  
  37. }  
  38. int _data3;  
  39. };  
  40.   
  41. int main()  
  42. {  
  43. cout<<"sizeof(Derive) = "<<sizeof(Derive)<<endl;  
  44. Derive d;  
  45. d._data1 = 0x01;  
  46. d._data2 = 0x02;  
  47. d._data3 = 0x03;  
  48. PrintVtable();  
  49. return 0;  
  50. }  

 

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

 

 

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

 

 

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

 

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

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
  1. class Base  
  2.   
  3. {  
  4. public:  
  5. virtual void FunTest1()  
  6. {  
  7. cout<<"Base::FunTest1()"<<endl;  
  8. }  
  9. virtual void FunTest2()  
  10. {  
  11. cout<<"Base::FunTest2()"<<endl;  
  12. }  
  13. int _data1;  
  14. };  
  15.   
  16. class Base1  
  17. {  
  18. public:  
  19. virtual void FunTest3()  
  20. {  
  21. cout<<"Base1::FunTest3()"<<endl;  
  22. }  
  23. virtual void FunTest4()  
  24. {  
  25. cout<<"Base1::FunTest4()"<<endl;  
  26. }  
  27. int _data2;  
  28. };  
  29. //这次将继承列表中Base和Base1的位置互换  
  30. class Derive:public Base1, public Base  
  31.   
  32. {  
  33. public:  
  34. virtual void FunTest1()  
  35. {  
  36. cout<<"Derive::FunTest1()"<<endl;  
  37. }  
  38. virtual void FunTest3()  
  39. {  
  40. cout<<"Derive::FunTest3()"<<endl;  
  41. }  
  42. virtual void FunTest5()  
  43. {  
  44. cout<<"Derive::FunTest5()"<<endl;  
  45. }  
  46. int _data3;  
  47. };  
  48.   
  49. int main()  
  50. {  
  51.            PrintVtable();  
  52. return 0;  
  53. }  

 

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

 

 

虚拟继承

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

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
  1. class Base  
  2.   
  3. {  
  4. public:  
  5. virtual void FunTest1()  
  6. {  
  7. cout<<"Base::FunTest1()"<<endl;  
  8. }  
  9. virtual void FunTest2()  
  10. {  
  11. cout<<"Base::FunTest2()"<<endl;  
  12. }  
  13. int _data1;  
  14. };  
  15.   
  16. class Derive:virtual public Base  
  17. {  
  18. public:  
  19. virtual void FunTest3()  
  20. {  
  21. cout<<"Derive::FunTest3()"<<endl;  
  22. }  
  23. virtual void FunTest4()  
  24. {  
  25. cout<<"Derive::FunTest4()"<<endl;  
  26. }  
  27. int _data2;  
  28. };  

 

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

 

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

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

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

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


0 0
原创粉丝点击