浅谈c++虚函数 虚继承的虚表剖析
来源:互联网 发布:织梦cms文档权限 编辑:程序博客网 时间:2024/06/09 00:06
1 虚函数的虚表剖析
(1)没有覆盖公有继承 派生类的虚表
class CBase //没有覆盖{public:virtual void FunTest0(){ cout << "CBase::FunTest0()"; }virtual void FunTest1(){ cout << "CBase::FunTest1()"; }virtual void FunTest2(){ cout << "CBase::FunTest2()"; }public:int data1;};class CDerived :public CBase{public:virtual void FunTest4(){ cout << "CDerived::FunTest4()"; }virtual void FunTest5(){ cout << "CDerived::FunTest5()"; }virtual void FunTest6(){ cout << "CDerived::FunTest6()"; }int data2;};typedef void(*FUN_TEST)(); //定义一个函数指针void PrintVF(){// 1种方法//for (int idx = 0; idx < 3;idx++)//{//FUN_TEST funTest = (FUN_TEST)(*((int*)*(int *)&b + idx));//// (int *)&b将b的地址值强转换成int*指针////*(int *)&b 将b的地址值取出来 0021fe04////(int*)*(int *)&b 将0021fe04 强转换成一个指针 +idx 指针里面的东西偏移idx单元////*((int*)*(int *)&b 将0021fe04 地址里面的值取出来//funTest();//cout << ": " << (int *)funTest << endl;//}CDerived d;d.data2 = 2;d.data1 = 1;cout << "CDerived的大小:" << sizeof(CDerived) << endl;cout << "CDerived vfptr:" << endl;FUN_TEST *funTest2 = (FUN_TEST*)(*(int*)&d);while (*funTest2){(*funTest2)();cout << ": " << *funTest2 << endl;funTest2++;}}剖析 虚表
说明:虚函数按声明顺序存在于虚表中;
在派生类中,前面是基类的虚函数,后面是派生类的虚函数
(2)有覆盖 的公有继承派生类的虚表
class CBase{public:CBase():data1(1){}virtual void FunTest0(){ cout << "CBase::FunTest0()" ; }virtual void FunTest1(){ cout << "CBase::FunTest1()" ; }virtual void FunTest2(){ cout << "CBase::FunTest2()" ; }virtual void FunTest3(){ cout << "CBase::FunTest3()" ; }int data1;};class CDerived :public CBase{public:CDerived():data2(2){}virtual void FunTest0(){ cout << "CDerived::FunTest0()" ; } //重写virtual void FunTest1(){ cout << "CDerived::FunTest1()" ; }//重写virtual void FunTest4(){ cout << "CDerived::FunTest4()" ; }virtual void FunTest5(){ cout << "CDerived::FunTest5()" ; }int data2;};typedef void(*_pFunTest)();void PrintVF() //打印虚表{CDerived derived;derived.data1 = 1;derived.data2 = 2;cout << "CDerived vfptr:" << endl;_pFunTest* pFunTest2 = (_pFunTest*)(*(int *)&derived);while (*pFunTest2){(*pFunTest2)();cout << ": " << *pFunTest2 << endl;pFunTest2++;}}void TestVirtual() // 测试调用基类还是派生类的虚表{CBase base;CDerived derived;CBase* PBase1 = &base; // 基类的指针指向基类,获取到的是基类的虚表PBase1->FunTest0(); //调用基类的FunTest0cout << endl;CBase* PBase2 = &derived;//基类的指针指向派生类,获取到的是派生类的虚表PBase2->FunTest0(); //掉用派生类FunTest0}虚表剖析
派生类虚表的形成: a.先拷贝基类的虚表
b.如果派生类重写了基类的虚函数,则修改同位置的基类虚函数
c.跟上派生类新定义的虚函数
调用虚表:通过基类的引用或指针调用虚函数时,调用基类还是派生类的虚函数,
要根据运行时引用或指针的实际指向的类型确定。
单继承的派生类的大小:虚表+ 基类的数据成员 + 派生类的成员
2 多继承
class Base1 //有覆盖{public:Base1():_data1(1){}virtual void Test1(){cout << "Base::Test1()";}virtual void Test2(){cout << "Base::Test2()";}virtual void Test3(){cout << "Base::Test3()";}int _data1;};class Base2{public:Base2():_data2(2){}virtual void Test4(){cout << "Base::Test4()" ;}virtual void Test5(){cout << "Base::Test5()" ;}virtual void Test6(){cout << "Base::Test6()" ;}int _data2;};class Derived :public Base1, public Base2{public:Derived():_data3(3){}virtual void Test1(){cout << "Derived::Test1()" ;}virtual void Test5(){cout << "Derived::Test5()" ;}virtual void Test7() //添加到Base1的虚表中{cout << "Derived::Test7()" ;}int _data3;};typedef void(*VFP)();void PrintVfp(){Derived d;d._data1 = 1;d._data2 = 2;d._data3 = 3;VFP* vfp = (VFP*)*(int *)&d;cout << "Derived vir table:" << endl;while (*vfp){(*vfp)();cout <<": "<< *vfp << endl;++vfp;}cout << endl;Base1& b1 = d;VFP* vfp1 = (VFP*)*(int *)&b1;cout << "Base1 vir table:" << endl;while (*vfp1){(*vfp1)();cout << ": " << *vfp1 << endl;++vfp1;}cout << endl;Base2& b2 = d;VFP* vfp2 = (VFP*)*(int *)&b2;cout << "Base2 vir table:" << endl;while (*vfp2){(*vfp2)();cout << ": " << *vfp2 << endl;++vfp2;}cout << endl;}数据模型: 虚表剖析:
(3)菱形继承
class Base{public:Base(){}virtual void Test1(){cout << "Base::Test1()";}int data1;};class C1 :public Base{public:virtual void Test1(){cout << "C1::Test1()";}virtual void Test2(){cout << "C1::Test2()";}int data2;};class C2 :public Base{public:virtual void Test1(){cout << "C2::Test1()";}virtual void Test3(){cout << "C2::Test3()";}int data3;};class D :public C1, public C2{public:virtual void Test1(){cout << "D::Test1()" ;}virtual void Test2(){cout << "D::Test2()" ;}virtual void Test3(){cout << "D::Test3()";}virtual void Test4(){cout << "D::Test4()";}int data4;};typedef void(*VFP)();void PrintVFP(){D d;d.C1::data1 = 0;d.C2::data1 = 1;d.data2 = 2;d.data3 = 3;d.data4 = 4;C1& c1 = d;VFP* vfp1 = (VFP*)*(int *)&c1;cout << "C1 vir table:" << endl;while (*vfp1){(*vfp1)();cout <<" : " <<*vfp1 << endl;++vfp1;}cout << endl;C2& c2 = d;VFP* vfp2 = (VFP*)*(int *)&c2;cout << "C2 vir table:" << endl;while (*vfp2){(*vfp2)();cout << " : " << *vfp2 << endl;++vfp2;}cout << endl;}虚表剖析: 数据模型:
说明: 如果派生类D有新的虚函数,则添加到第一继承顺序的基类c1的虚表后面
该菱形继承存在二义性,c1和c2中都继承了base的成员变量
菱形继承的大小:28 c1(虚表指针+base成员+c1成员 12) + c2(12) + 派生类D的成员
2 虚继承
(1)单继承
class Base{public:Base():data1(33){}virtual void Test1(){cout << "Base::Test1()";}virtual void Test2(){cout << "Base::Test2()";}virtual void Test3(){cout << "Base::Test3()";}int data1;};class Derived :virtual public Base{public:Derived() // 1填写偏移量表格地址 2调用基类构造函数(填写基类虚表地址) 3填写派生类虚表地址 //4 重新填写属于基类对象部分的虚表地址(用派生类的虚表) 5派生类对象和基类对象之间用0分割(虚拟继承中有构造或析构才会用0){}~Derived(){}virtual void Test1(){cout << "Derived::Test1()";}virtual void Test3(){cout << "Derived::Test3()" ;}virtual void Test4() // 屏蔽掉 大小为16 没有第一个虚表{cout << "Derived::Test4()";}int data2;};void TestSize(){Derived d;d.data1 = 1;d.data2 = 2;cout << sizeof(Derived) << endl; // 24 去掉析构函数和构造函数 20 多加四个字节}typedef void(*VFP)();void PrintVfp(){Derived d;d.data1 = 1;d.data2 = 2;VFP* vfp = (VFP*)*(int *)&d;cout << "Derived vir table 1:" << endl;while (*vfp){(*vfp)();cout << ": " << *vfp << endl;++vfp;}cout << endl;Base& b = d;VFP* vfp1 = (VFP*)*(int *)&b;cout << "Derived vir table: 2 Base" << endl;while (*vfp1){(*vfp1)();cout << ": " << *vfp1 << endl;++vfp1;}cout << endl;}虚表剖析:
a 没有构造函数和析构函数(少中间的0 四个字节),派生类有新的虚函数
b 没有构造函数和构造函数(少中间的0 四个字节) c。有构造函数或者析构函数
派生类没有新的虚函数 派生类新定义了虚函数
简述一下构造函数的作用:(派生类的构造函数做了什么)
(2)多继承
没有考虑构造函数或析构函数 ,派生类定义了新虚函数
class C1{public:virtual void Test1(){cout << "C1::Test1()";}virtual void Test2(){cout << "C1::Test2()";}int data1;};class C2{public:virtual void Test3(){cout << "C2::Test3()";}virtual void Test4(){cout << "C2::Test4()";}int data2;};class D :public virtual C1, public virtual C2{public:virtual void Test1() //重写c1的Test1{cout << "D::Test1()";}virtual void Test3() //重写c2的Test3{cout << "D::Test3()";}virtual void Test5() //派生类特有的Test5{cout << "D::Test5()";}int data3;};typedef void(*VFP)();void PrintVfp(){D d;d.data3 = 3;d.data2 = 2;d.data1 = 1;VFP* vfp3 = (VFP*)*(int *)&d;cout << " 派生类自己特有的虚表:" << endl;while (*vfp3){(*vfp3)();cout << ": " << *vfp3 << endl;++vfp3;}cout << endl;C1& c1 = d;VFP* vfp1 = (VFP*)*(int *)&c1;cout << " c1的虚表:" << endl;while (*vfp1){(*vfp1)();cout << ": " << *vfp1 << endl;++vfp1;}cout << endl;C2& c2 = d;VFP* vfp2 = (VFP*)*(int *)&c2;cout << " c2的虚表:" << endl;while (*vfp2){(*vfp2)();cout << ": " << *vfp2 << endl;++vfp2;}cout << endl;}剖析虚表:
(3)菱形虚拟继承,解决了二义性
没有构造函数或析构函数,派生类类定义了新的虚函数
class Base{public:Base():_data1(0){}virtual void Test1(){cout << "Base::Test1()" ;}int _data1;};class C1 :virtual public Base{public:virtual void Test1(){cout << "C1::Test1()" ;}virtual void Test2(){cout << "C1::Test2()" ;}int _data2;};class C2 :virtual public Base{public:virtual void Test1(){cout << "C2::Test1()" ;}virtual void Test3(){cout << "C2::Test3()" ;}int _data3;};class D :public C1, public C2{public:virtual void Test1(){cout << "D::Test1()" ;}virtual void Test2(){cout << "D::Test2()" ;}virtual void Test3(){cout << "D::Test3()" ;}virtual void Test4(){cout << "D::Test4()";}int _data4;};typedef void(*VFP)();void PrintVfp(){D d;d._data1 = 1;d._data2 = 2;d._data3 = 3;d._data4 = 4;C1& c1 = d;VFP* vfp1 = (VFP*)*(int *)&c1;cout << " vir table up:" << endl;while (*vfp1){(*vfp1)();cout << ": " << *vfp1 << endl;++vfp1;}cout << endl;C2& c2 = d;VFP* vfp2 = (VFP*)*(int *)&c2;cout << " vir table mid:" << endl;while (*vfp2){(*vfp2)();cout << ": " << *vfp2 << endl;++vfp2;}cout << endl;Base& b = d;VFP* vfp3 = (VFP*)*(int *)&b;cout << " vir table down:" << endl;while (*vfp3){(*vfp3)();cout << ": " << *vfp3 << endl;++vfp3;}cout << endl;}
- 浅谈c++虚函数 虚继承的虚表剖析
- c++中虚函数继承,虚表剖析
- [C++]虚函数的虚继承
- C++,继承、虚函数解惑!
- C++,继承、虚函数解惑!
- 浅谈虚函数的应用,以及虚函数在继承时应该注意的地方
- C++: 浅谈虚函数、纯虚函数
- 虚函数表剖析
- C++多继承虚函数类内部模型结构剖析
- 虚函数的继承
- 菱形继承与菱形虚继承剖析
- 【C++】c++单继承、多继承、菱形继承内存布局(虚函数表结构)
- 【C++】c++单继承、多继承、菱形继承内存布局(虚函数表结构)
- 【C++】虚函数和虚继承的内存分布情况
- 类的继承、抽象类、虚函数[C++]
- 【C++】内联inline、继承、重载与虚函数的解释
- c/c++----------虚函数、虚继承、纯虚函数
- 浅谈C++中的虚继承
- dubbo_ Linux安装配置
- 自己写属于自己的printf()函数
- 利用maven创建spring-osgi powered 多bundle工程
- 第二十六讲项目4-本月有几天
- C# DataTable的詳細用法
- 浅谈c++虚函数 虚继承的虚表剖析
- elasticsearch安装
- MyEclipse2015创建Maven WebAPP出现GC overhead limit exceeded错误
- 《大数据工程师(开发)面试系列(1)》
- java 数据类型
- Ajax在JQuery的运用(load方法练习)
- QT动态链接库(DLL)的创建和调用
- 改不了名字?
- fragment与Activity之间数据的传递