c++中的多态和多态对象模型

来源:互联网 发布:华夏免费版数据库 编辑:程序博客网 时间:2024/06/08 18:48

1.什么是多态?

多态顾名思义,就是“多种形态”

在c++中,我们是通过虚函数来实现多态的

那么什么是虚函数呢?

虚函数就是在类的成员函数的前面加上virtual关键字,那么该成员函数就是虚函数

在c++中多态形成的条件是什么呢?

1.虚函数的重写;

2.父类的指针或引用调用重写的虚函数。

class A{public:        virtual void f1(){cout<<"A::f1()"<<endl;}};class B : public A{public:virtual void f1(){cout<<"B::f1()"<<endl;}};void Test(){B b;//b是一个子类对象A *p = &b;//此时形成了多态,这个时候调用函数与类型无关,只与指向对象有关,指向谁就调用谁}
在这里我们进行了虚函数的重写,什么是虚函数的重写呢?

当子类定义了一个和父类完全相同的虚函数(返回值、函数名、可变参数列表)时,则称为重写。

特例:协变 A类虚函数的返回值可定义为A类的指针或引用 B类也是可以定义为B类的。(可以看做是切片类型)

//特例class A{public:A* fun(){}};class B : public A{public:B* fun(){}//此时也构成了重写};


2.单继承&多继承

1. 单继承:一个类只有一个直接父类时称这个继承关系为单继承
2. 多继承:一个类有两个或以上直接父类时称这个继承关系为多继承

在这里需要了解一下虚表

虚表就是存了虚函数的表

虚函数能够实现多态的重要原因是有一个虚表指针指向了虚函数表,这样就可以通过指针来找到xuhans


单继承

//打印虚表typedef void(*V_FUNC)(); //定义一个函数指针void PrintVtable(int* vtable){printf("vtable 0x%p\n",vtable);int** ppvtable = (int**)vtable;for(size_t i=0; ppvtable[i]!=0; i++){printf("vatable[%u]::0x%p->",i,ppvtable[i]);V_FUNC f = (V_FUNC)ppvtable[i];f();}}//单继承class Base{public:virtual void fun1(){cout<<"Base::fun1()"<<endl;}virtual void fun2(){cout<<"Base::fun2()"<<endl;}private:int _a;};class Derive : public Base{public:virtual void fun1(){cout<<"Derive::fun1()"<<endl;}virtual void fun3(){cout<<"Derive::fun1()"<<endl;}};int main(){Base b;Derive d;PrintVtable(*((int**)&b));PrintVtable(*((int**)&d));return 0;}
通过调试监视窗口,我们可以发现单继承的对象模型


多继承

//打印虚表typedef void(*V_FUNC)(); //定义一个函数指针void PrintVtable(int* vtable){printf("vtable 0x%p\n",vtable);int** ppvtable = (int**)vtable;for(size_t i=0; ppvtable[i]!=0; i++){printf("vatable[%u]::0x%p->",i,ppvtable[i]);V_FUNC f = (V_FUNC)ppvtable[i];f();}}//多继承class Base1{public:void virtual Fun1(){cout<<"Base1::Fun1()"<<endl;}void virtual Fun2(){cout<<"Base1::Fun2()"<<endl;}private:int _b;};class Base2{public:void virtual Fun1(){cout<<"Base2::Fun1()"<<endl;}void virtual Fun3(){cout<<"Base2::Fun3()"<<endl;}private:int _b;};class Derive:public Base1,public Base2{public:void virtual Fun1(){cout<<"Derive::Fun1()"<<endl;//覆盖}void virtual Fun3(){cout<<"Derive::Fun3()"<<endl;}private:int _d;};int main(){Base1 b1;Base2 b2;Derive d;PrintVtable(*((int**)&b1));PrintVtable(*((int**)&b2));PrintVtable(*((int**)&d));PrintVtable(*((int**)((char*)&d+sizeof(Base1))));return 0;}


多继承及其对象模型


3.菱形虚拟继承


//打印虚表typedef void(*V_FUNC)(); //定义一个函数指针void PrintVtable(int* vtable){printf("vtable 0x%p\n",vtable);int** ppvtable = (int**)vtable;for(size_t i=0; ppvtable[i]!=0; i++){printf("vatable[%u]::0x%p->",i,ppvtable[i]);V_FUNC f = (V_FUNC)ppvtable[i];f();}}//菱形继承class Base{public:void virtual Fun1(){cout<<"Base::Fun1()"<<endl;}void virtual Fun2(){cout<<"Base::Fun2()"<<endl;}public:int _b;};class Derive1:virtual public Base{public:void virtual Fun1(){cout<<"Derive1::Fun1()"<<endl;}void virtual Fun3(){cout<<"Derive1::Fun3()"<<endl;}public:int _d1;};class Derive2:virtual public Base{public:void virtual Fun1(){cout<<"Derive2::Fun1()"<<endl;}void virtual Fun4(){cout<<"Derive2::Fun4()"<<endl;}public:int _d2;};class Derive:public Derive1,public Derive2{public:void virtual Fun1(){cout<<"Derive::Fun1()"<<endl;//覆盖}void virtual Fun5(){cout<<"Derive::Fun5()"<<endl;}public:int _d;};int main(){Derive d;d._b = 2;d._d1 = 3;d._d2 = 4;d._d = 5;PrintVtable(*((int**)&d));return 0;}

菱形虚拟继承的对象模型


这里写图片描述

在我们的菱形虚拟继承中,又有虚表也有虚基表,那么就需要我们在编译代码中看看内存中的状况,在图中我们可以看到,我们把基类的对象存为共有的,因此需要用虚基表用偏移量找到他。这里注意虚函数的重写,因为看的是Derive的对象模型,所以在继承的时候,有的函数进行了重写。

原创粉丝点击