多态中的模型

来源:互联网 发布:网络中央控制主机 编辑:程序博客网 时间:2024/05/20 15:59

一、虚表

关于什么是虚表?我们通过一段代码来认识一下虚表:

#include<iostream>using namespace std;class Base{public:Base()//普通构造函数{_b = 1;}protected:int _b;};int main(){cout << sizeof(Base) << endl;system("pause");return 0;}

#include<iostream>using namespace std;class Base{public:virtual ~Base()//析构函数为虚函数{}protected:int _b;};int main(){cout << sizeof(Base) << endl;system("pause");return 0;}


我们来比较一下这两段代码,第二段代码只是使用了虚函数就多出了4个字节。为什么?!我们再来看看它们的内存



对于有虚函数的类,编译器都会维护一张虚表,对象的前四个字节就是指向虚表的指针。

二、没有覆盖的单继承的模型

先来看一段代码:

#include<iostream>using namespace std;class Base{public:Base(){_b = 10;}virtual void FunTest1(){cout << "Base::Funtest1()" << endl;}virtual void FunTest2(){cout << "Base::Funtest2()" << endl;}virtual void FunTest3(){cout << "Base::Funtest3()" << endl;}protected:int _b;};class Derived :public Base{public:virtual void FunTest4(){cout << "Derived::Funtest4()" << endl;}virtual void FunTest5(){cout << "Derived::Funtest5()" << endl;}virtual void FunTest6(){cout << "Derived::Funtest6()" << endl;}};int main(){Base b;Derived d;system("pause");return 0;}


我们来看看它们的内存存储方式:



虚函数按其声明顺序存在于虚表中;在派生类中,前面是基类的虚函数,后面是派生类的虚函数。

三、有覆盖的单继承模型

先看一段代码:

#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;}};class Derived :public Base{public:virtual void FunTest1(){cout << "Derived::Funtest4()" << endl;}virtual void FunTest2(){cout << "Derived::Funtest5()" << endl;}virtual void FunTest4(){cout << "Derived::Funtest6()" << endl;}};int main(){Base b;Derived d;system("pause");return 0;}


可以看出FunTest1()和FunTest2()在派生类中被重写。我们来看看它们的存储方式发生了什么变化:



派生类的虚函数表生成:

1.先拷贝基类的虚表函数;

2.如果派生类重写了基类的某个虚函数,就替换同位置的基类虚函数;

3.跟上派生类自己新定义的虚函数。

四、有覆盖的多继承

先来看一段代码:

#include<iostream>using namespace std;class Base1{public:Base1(){_b1 = 1;}virtual void FunTest1(){cout << "Base1::Funtest1()" << endl;}protected:int _b1;};class Base2{public:Base2(){_b2 = 2;}virtual void FunTest2(){cout << "Base2::Funtest2()" << endl;}protected:int _b2;};class Derived :public Base1,public Base2{public:Derived(){_d = 10;}virtual void FunTest1(){cout << "Derived::Funtest1()" << endl;}virtual void FunTest2(){cout << "Derived::Funtest2()" << endl;}virtual void FunTest3(){cout << "Derived::Funtest3()" << endl;}protected:int _d;};int main(){Base1 b1;Base2 b2;Derived d;system("pause");return 0;}


我们来看看它们在内存中的存储结构:

因为FunTest1()和FunTest2()函数都在派生类里被重写,所以派生类里的FunTest1()和FunTest2()覆盖了基类里的。

五、有覆盖的菱形继承

先看一段代码:

#include<iostream>using namespace std;class Base1{public:Base1(){_b1 = 1;}virtual void FunTest1(){cout << "Base1::Funtest1()" << endl;}protected:int _b1;};class Base2:public Base1{public:Base2(){_b2 = 2;}virtual void FunTest2(){cout << "Base2::Funtest2()" << endl;}protected:int _b2;};class Base3 :public Base1{public:Base3(){_b3 = 3;}virtual void FunTest3(){cout << "Base3::Funtest3()" << endl;}protected:int _b3;};class D :public Base2, public Base3{public:D(){_d = 4;}virtual void FunTest1(){cout << "D::Funtest1()" << endl;}virtual void FunTest2(){cout << "D::Funtest2()" << endl;}virtual void FunTest3(){cout << "D::Funtest3()" << endl;}virtual void FunTest4(){cout << "D::Funtest4()" << endl;}protected:int _d;};int main(){Base1 b1;Base2 b2;Base3 b3;D d;system("pause");return 0;}


看看它们的存储方式:


在菱形继承中,D派生类里新增的成员函数被插在内存第一个对象虚表的最后一个位置,Base1,Base2,Base3里被D重写的虚函数,在虚表里全部被D派生类替换。


六、菱形虚拟继承

先来看一段代码:

#include<iostream>using namespace std;class Base1{public:Base1(){_b1 = 1;}virtual void FunTest1(){cout << "Base1::Funtest1()" << endl;}protected:int _b1;};class Base2:virtual public Base1{public:Base2(){_b2 = 2;}virtual void FunTest2(){cout << "Base2::Funtest2()" << endl;}protected:int _b2;};class Base3 :virtual public Base1{public:Base3(){_b3 = 3;}virtual void FunTest1(){cout << "Base3::Funtest1()" << endl;}virtual void FunTest3(){cout << "Base3::Funtest3()" << endl;}protected:int _b3;};class D :public Base2, public Base3{public:D(){_d = 4;}virtual void FunTest2(){cout << "D::Funtest2()" << endl;}virtual void FunTest3(){cout << "D::Funtest3()" << endl;}virtual void FunTest4(){cout << "D::Funtest4()" << endl;}protected:int _d;};int main(){Base1 b1;Base2 b2;Base3 b3;D d;system("pause");return 0;}






0 0