虚函数怎么调用: (1)先找到虚函数表 (2)从虚表中找到要调用的虚函数。
单继承中派生类虚表的形成: 先看下述的代码:
#include <iostream> using namespace std; //基类中包含虚函数和普通函数 class Base { public: virtual void FunTest1() { cout<<"Base::FunTest1()"<<endl; } virtual void FunTest2() { cout<<"Base::FunTest2()"<<endl; } virtual void FunTest3() { cout<<"Base::FunTest3()"<<endl; } void FunTest4() { cout<<"Base::FunTest4()"<<endl; } protected: int _b; }; class Derived: public Base { public: virtual void FunTest1() { cout<<"Derived::FunTest1()"<<endl; } virtual void FunTest3() { cout<<"Derived::FunTest3()"<<endl; } virtual void FunTest5() { cout<<"Derived::FunTest5()"<<endl; } public: int _d; }; typedef void (*PFun)(); void Print() { Base b; PFun* pFun = (PFun*)(*(int*)&b); while(*pFun) { (*pFun)(); pFun++; } } void FunTest(Base &b) { b.FunTest3(); } int main() { Base b; Derived d; FunTest(b); FunTest(d); cout<<sizeof(b)<<endl; cout<<sizeof(d)<<endl; Print(); cout<<endl; system("pause"); return 0; }运行结果: 基类和派生类用的不是同一张虚表,如果派生类没有重写基类的虚函数的话,那么派生类就拷贝基类的虚函数,如果派生类重写基类的虚函数的话,那么他就会改写相同位置上的虚函数。 总结: 派生类形成虚表: (1)先拷贝了基类的虚表(无重写函数) (2)若有重写函数,覆盖原来相同位置上的虚函数,即就是在派生类中如果重写FunTest1()函数,则基类中原有的FunTest1()函数被覆盖 (3)如果派生类有新增的虚函数,则在虚表后面加上派生类新增的虚函数。
多继承中派生类虚表的形成: 先看下述的代码:
#include <iostream> using namespace std; //基类Base1和Base2 class Base1 { public: virtual void FunTest1() { cout<<"Base1::FunTest1()"<<endl; } virtual void FunTest2() { cout<<"Base1::FunTest2()"<<endl; } protected: int _b1; }; class Base2 { public: virtual void FunTest3() { cout<<"Base2::FunTest3()"<<endl; } virtual void FunTest4() { cout<<"Base2::FunTest4()"<<endl; } protected: int _b2; }; class Derived: public Base1, public Base2 { public: virtual void FunTest2() { cout<<"Derived::FunTest2()"<<endl; } virtual void FunTest3() { cout<<"Derived::FunTest3()"<<endl; } virtual void FunTest5() { cout<<"Derived::FunTest5()"<<endl; } public: int _d; }; typedef void (*PFun)(); void Print() { Derived d; Base1 &b1 = d; PFun* pFun = (PFun*)(*(int*)&b1); while(*pFun) { (*pFun)(); pFun++; } Base2 &b2 = d; pFun = (PFun*)(*(int*)&b2); while(*pFun) { (*pFun)(); pFun++; } } void FunTest() { Derived d; Base1* pb = (Base1*)&d; pb->FunTest2(); } int main() { Base1 b1; Base2 b2; Derived d; cout<<sizeof(b1)<<endl; cout<<sizeof(b2)<<endl; cout<<sizeof(d)<<endl; Print(); cout<<endl; FunTest(); cout<<endl; system("pause"); return 0; }运行结果:
接下来分析一下该派生类的对象模型: 如果把派生类中基类的顺序调换一下,则派生类中原有的虚函数在虚表中的位置会发生变化, 代码如下:
class Derived: public Base2, public Base1 { public: virtual void FunTest2() { cout<<"Derived::FunTest2()"<<endl; } virtual void FunTest3() { cout<<"Derived::FunTest3()"<<endl; } virtual void FunTest5() { cout<<"Derived::FunTest5()"<<endl; } public: int _d; };运行结果图:
由上述结果可以看出,派生类的新增加的虚函数在虚表中的位置是和继承的顺序是有关联的,如果先继承Base1类,则派生类的新增加的虚函数在Base1虚表中,如果先继承Base2类,则派生类的新增加的虚函数在Base2虚表中.
菱形继承中派生类虚表的形成: 先看下述的代码:
#include <iostream> using namespace std; class B { public: virtual void FunTest1() { cout<<"B::FunTest1()"<<endl; } public: int _b; }; class C1:public B { public: virtual void FunTest2() { cout<<"C1::FunTest2()"<<endl; } public: int _c1; }; class C2:public B { public: virtual void FunTest1() { cout<<"C2::FunTest1()"<<endl; } virtual void FunTest3() { cout<<"C1::FunTest3()"<<endl; } public: int _c2; }; class D: public C1, public C2 { public: virtual void FunTest2() { cout<<"D::FunTest2()"<<endl; } virtual void FunTest3() { cout<<"D::FunTest3()"<<endl; } virtual void FunTest4() { cout<<"Derived::FunTest4()"<<endl; } public: int _d; }; typedef void (*PFun)(); void Print() { D d; C1 &c1 = d; PFun* pFun = (PFun*)(*(int*)&c1); while(*pFun) { (*pFun)(); pFun++; } C2 &c2 = d; pFun = (PFun*)(*(int*)&c2); while(*pFun) { (*pFun)(); pFun++; } } int main() { C1 c1; C2 c2; D d; d.C1::_b = 0; d.C2::_b = 1; d._c1 = 3; d._c2 = 4; d._d = 5; cout<<sizeof(c1)<<endl; cout<<sizeof(c2)<<endl; cout<<sizeof(d)<<endl; cout<<endl; Print(); cout<<endl; system("pause"); return 0; }运行结果图:
接下来分析一下该派生类的对象模型:
因为菱形继承存在二义性,所以接下来看看虚继承的虚表: 虚拟继承中派生类虚表的形成: 先看下述的代码:
#include <iostream> using namespace std; class B { public: virtual void FunTest1() { cout<<"B::FunTest1()"<<endl; } virtual void FunTest2() { cout<<"B::FunTest2()"<<endl; } public: int _b; }; class C:virtual public B { public: virtual void FunTest1() { cout<<"C::FunTest1()"<<endl; } virtual void FunTest3() { cout<<"C::FunTest3()"<<endl; } public: int _c; }; typedef void (*PFun)(); void Print() { C c; PFun* pFun = (PFun*)(*(int*)&c); while(*pFun) { (*pFun)(); pFun++; } B &b = c; pFun = (PFun*)(*(int*)&b); while(*pFun) { (*pFun)(); pFun++; } } int main() { C c; B b; c._b = 0; c._c = 1; cout<<sizeof(b)<<endl; cout<<sizeof(c)<<endl; cout<<endl; Print(); cout<<endl; system("pause"); return 0; }运行结果图:
接下来分析一下该派生类的对象模型:
虚拟继承与普通继承的区别: (1)虚拟继承多传了一个参数1(虚拟地址的标志位),看是否为虚拟继承 (2)虚拟继承多个地址存放虚拟地址空间 下面举个小例子:
#include <iostream> using namespace std; class B { public: virtual void FunTest1() { cout<<"B::FunTest1()"<<endl; } virtual void FunTest2() { cout<<"B::FunTest2()"<<endl; } public: int _b; }; class C1:virtual public B { public: virtual void FunTest1() { cout<<"C1::FunTest1()"<<endl; } virtual void FunTest3() { cout<<"C1::FunTest3()"<<endl; } public: int _c1; }; class C2:public B { public: virtual void FunTest1() { cout<<"C2::FunTest1()"<<endl; } virtual void FunTest3() { cout<<"C2::FunTest3()"<<endl; } public: int _c2; }; typedef void (*PFun)(); void Print() { cout<<"C1:"<<endl; C1 c1; PFun* pFun = (PFun*)(*(int*)&c1); while(*pFun) { (*pFun)(); pFun++; } B &b = c1; pFun = (PFun*)(*(int*)&b); while(*pFun) { (*pFun)(); pFun++; } cout<<endl; cout<<"C2:"<<endl; C2 c2; pFun = (PFun*)(*(int*)&c2); while(*pFun) { (*pFun)(); pFun++; } B &b1 = c2; pFun = (PFun*)(*(int*)&b1); while(*pFun) { (*pFun)(); pFun++; } } int main() { C1 c1; C2 c2; B b; c1._b = 1; c1._c1 = 2; c2._b = 3; c2._c2 = 4; cout<<sizeof(c1)<<endl; cout<<sizeof(c2)<<endl; cout<<endl; Print(); cout<<endl; system("pause"); return 0; }运行结果图:
对象模型图:
菱形虚拟继承中派生类虚表的形成: 先看下述的代码:
#include <iostream> using namespace std; class B { public: virtual void FunTest1() { cout<<"B::FunTest1()"<<endl; } public: int _b; }; class C1:virtual public B { public: virtual void FunTest2() { cout<<"C1::FunTest2()"<<endl; } public: int _c1; }; class C2:virtual public B { public: virtual void FunTest1() { cout<<"C2::FunTest1()"<<endl; } virtual void FunTest3() { cout<<"C1::FunTest3()"<<endl; } public: int _c2; }; class D: public C1, public C2 { public: virtual void FunTest2() { cout<<"D::FunTest2()"<<endl; } virtual void FunTest3() { cout<<"D::FunTest3()"<<endl; } virtual void FunTest4() { cout<<"D::FunTest4()"<<endl; } public: int _d; }; typedef void (*PFun)(); void Print() { D d; C1 &c1 = d; PFun* pFun = (PFun*)(*(int*)&c1); while(*pFun) { (*pFun)(); pFun++; } C2 &c2 = d; pFun = (PFun*)(*(int*)&c2); while(*pFun) { (*pFun)(); pFun++; } B &b = d; pFun = (PFun*)(*(int*)&b); while(*pFun) { (*pFun)(); pFun++; } } int main() { C1 c1; C2 c2; D d; d.C1::_b = 0; d.C2::_b = 1; d._c1 = 3; d._c2 = 4; d._d = 5; cout<<sizeof(c1)<<endl; cout<<sizeof(c2)<<endl; cout<<sizeof(d)<<endl; cout<<endl; Print(); cout<<endl; system("pause"); return 0; }运行结果图: 由结果图可以看出,这种方法保证菱形继承中基类只被继承一次,不会出现二义性的问题。 对象模型分析: