C++中多态与多态对象模型

来源:互联网 发布:人物简笔画软件 编辑:程序博客网 时间:2024/06/05 11:31

一、什么是多态?

多态,其实就是多种形态——动态形态和静态形态(即重载)。同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。通俗的说,就是两个函数同名,但参数列表不同,然后根据参数不同实现不同的功能, 即“一个接口,多种方法”。
构成多态条件有:虚函数的重写(覆盖)
父类(基类)的指针或者引用指向对象
在进行多态的单/多继承模型之前,我首先谈一下对虚函数,虚表的认识。
虚函数是C++实现多态的方式。类的成员函数前加virtual关键字,则这个成员函数称为虚函数。(虚函数的子类可以不写virtual)。
注意:只有类的非静态成员函数才能定义为虚函数
构造函数不能定义为虚函数(虚函数与虚表有关,虚表那时还未初始化好)
虚函数表是通过一块连续的内存存储虚函数地址的地址。
接下来我对函数的重载,重写和重定义做一下总结和比较。
这里写图片描述
重载举例

int Add(int a,int b);double Add(double a,double b);

重写举例

class Person{public : virtual void BuyTickets() { cout<<" 买票"<< endl; }protected : string _name ; // 姓名};class Student : public Person{public :  virtual void BuyTickets() { cout<<" 买票-半价 "<<endl ; }protected : int _num ; //学号};int main(){    Student a;    a.BuyTickets();//调用的是自己的BuyTickets(),而不是继承来自基类的    return 0;}

重定义(同名隐藏)举例

class Person{public :  void BuyTickets() { cout<<" 买票"<< endl; }protected : string _name ; // 姓名};class Student : public Person{public :   void BuyTickets() { cout<<" 买票-半价 "<<endl ; }protected : int _num ; //学号};int main(){    Student a;    a.BuyTickets();//调用的是派生类自己重定义的BuyTickets(),而不是继承来自基类的    return 0;}

二、多态的单继承模型

#include<iostream>#include<assert.h>#include<windows.h>using namespace std;typedef void(*Func);class Base{public:    virtual void Func1()    {        cout<<"Base::Func1"<<endl;    }    virtual void Func2()    {        cout<<"Base::Func2"<<endl;    }private:    int a;};class Derive:public Base{public:    virtual void Func1()    {        cout<<"Base::Func1"<<endl;    }    virtual void Func3()    {        cout<<"Base::Func3"<<endl;    }    virtual void Func4()    {        cout<<"Base::Func4"<<endl;    }private:    int b;};typedef void (*FUNC)();void PrintVTable (int* VTable){    cout<<" 虚表地址>"<< VTable<<endl ; for (int i = 0; VTable[i ] != 0; ++i) { printf(" 第%d个虚函数地址 :0X%x,->", i , VTable[i ]); FUNC f = (FUNC) VTable[i]; f(); } cout<<endl ;}void Test1(){    Base b1;    Derive b2;    int* VTable1 = (int*)(*(int*)&b1);    int* VTable2 = (int*)(*(int*)&b2);    PrintVTable(VTable1 );    PrintVTable(VTable2 );}int main(){    Test1();    return 0;    system("pause");}

可以看到派⽣类Derive::func1重写基类Base::func1,覆盖了相应虚表位置上的函数。
ps:可以看到这⾥没有看到派⽣类Derive中的func3和func4,这两个函数就放在func2
的后⾯,这⾥没有显⽰是VS的问题(bug)
这里写图片描述
这里写图片描述
单继承对象模型
这里写图片描述
多重继承中,子类会同时重写多个父类中相同的函数,并且子类将自己的虚函数存放在第一个继承的虚函数表中。子类没有自己的虚表,继承第一个父类的虚表。

三:多态的多继承模型

#include<iostream>#include<assert.h>#include<windows.h>using namespace std;typedef void(*Func);class Base1{public : virtual void func1() { cout<<"Base1::func1" <<endl; } virtual void func2() { cout<<"Base1::func2" <<endl; }private : int b1 ;};class Base2{public : virtual void func1() { cout<<"Base2::func1" <<endl; } virtual void func2() { cout<<"Base2::func2" <<endl; }private : int b2 ;};class Derive : public Base1, public Base2{public : virtual void func1() { cout<<"Derive::func1" <<endl; } virtual void func3() { cout<<"Derive::func3" <<endl; }private : int d1 ;};typedef void (* FUNC) ();void PrintVTable (int* VTable){ cout<<" 虚表地址>"<< VTable<<endl ; for (int i = 0; VTable[i ] != 0; ++i) { printf(" 第%d个虚函数地址 :0X%x,->", i , VTable[i ]); FUNC f = (FUNC) VTable[i ]; f(); } cout<<endl ;}void Test1 (){ Derive d1 ; int* VTable = (int*)(*( int*)&d1 ); PrintVTable(VTable ); // Base2虚函数表在对象Base1后⾯ VTable = (int *)(*((int*)&d1 + sizeof (Base1)/4)); PrintVTable(VTable );}int main(){    Test1();    return 0;    system("pause");}

这里写图片描述
这里写图片描述

四、菱形继承和菱形虚拟继承

这里写图片描述
菱形继承对象模型
这里写图片描述
Assistant的对象中有两份Person成员
菱形继承存在二义性和数据冗余的问题

class Person{public : string _name ; // 姓名};class Student : public Person{protected : int _num ; //学号};class Teacher : public Person{protected : int _id ; };class Assistant : public Student, public Teacher{protected : string _majorCourse ; // 主修课程};void Test (){ Assistant a ; a.Student ::_name = "xxx"; a.Teacher ::_name = "yyy";}

菱形虚拟继承对象模型
这里写图片描述

#include<iostream>#include<assert.h>#include<windows.h>using namespace std;typedef void(*Func);class A  {  public:      virtual void f1()      {          cout<<"A::f1"<<endl;      }      virtual void f2()      {          cout<<"A::f2"<<endl;      }  public:      int _a;  };  class B : virtual public A  {  public:      virtual void f1()      {          cout<<"B::f1"<<endl;      }      virtual void f3()      {          cout<<"B::f3"<<endl;      }  public:      int _b;  };  class C : virtual public A  {  public:      virtual void f1()      {          cout<<"C::f1"<<endl;      }      virtual void f3()      {          cout<<"C::f3"<<endl;      }  public:      int _c;  };  class D : public B, public C  {  public:      virtual void f1()      {          cout<<"D::f1"<<endl;      }      virtual void f4()      {          cout<<"D::f4"<<endl;      }  public:      int _d;  };  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("vtable[%d]:0x%p->", i,ppVtable[i]);          V_FUNC f = (V_FUNC)ppVtable[i];        f();    }      cout<<"---------------------------------------------------"<<endl;  }  int main()  {      D d;      d.B::_a = 1;      d._b = 2;      d.C::_a = 3;      d._c = 4;      d._d = 5;      cout<<sizeof(B)<<endl;    //B    PrintVTable(*((int**)&d));      // C      PrintVTable(*((int**)((char*)&d+sizeof(B)-sizeof(A))));      // A      PrintVTable(*((int**)((char*)&d+sizeof(D)-sizeof(A))));      return 0;  }  

这里写图片描述
这里写图片描述

原创粉丝点击