• C++中的多态和多态对象模型


    什么是多态

    所谓多态,也就是说“多种形态”
    C++中虚函数就是为了实现多态
    虚函数–类的成员函数前面加上virtual关键字,则这个函数就是虚函数
    多态的形成条件:
    1、虚函数的重写 2、父类的指针或者引用调用重写的虚函数
    例如:A*p = & b;
    A是一个父类,b是一个子类对象
    这个时候就是形成了多态。这个时候调用函数与类型无关,只与指向的对象有关,指向谁就调用谁。

    虚函数的重写:

    当子类定义了一个与父类完全相同的虚函数(返回值,参数同,函数名)时,则称这个函数重写
    特例:协变 A类虚函数的返回值可定义为A类的指针或引用 B类也是可以定义为B类的。(可以看做是切片类型)

    class A
    {
    public:
    A* Fun()
    {}
    }
    class B :public A
    {
    public:
    B* Fun()
    {}
    //在这里Fun函数就构成了重写,(协变)
    }
    

    单继承和多继承

    单继承:

    在这里要了解一下虚表:就是一个保存了虚函数的表
    虚函数实现多态的原因就是因为有一个虚表指针指向虚函数表,这样就可以通过指针来找到虚函数

    //打印虚表的函数
    //单继承,多继承都会用
    //32位平台下,指针是4个字节,我们只需要把它取出来就能把虚函数的地址打印出来了
    typedef void(*V_FUNC)();//这里定义一个函数指针
    void PrintVTable(int vtable)
    {
        int *VfArray = (int*) vtable;
        printf("vtable:0x%p
    ",VfArray);
        for(size_t i = 0;VfArray[i]!=0;++i)
        {
            printf("vfunc[%d]:0x%p
    ",i,VfArray);
            V_FUNC f = (V_FUNC) VfArray[i];
            f();
        }
        cout<<"=================================";
    }
    

    单继承的代码:

    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::Fun3()"<<endl;
        }
    private:
    
    };
    
    int main()
    {
        Base b;
        Derive d;
        PrintVTable(*((int*)&b));
        PrintVTable(*((int*)&d));
    
    }

    单继承的对象模型如下图

    这里写图片描述

    多继承

    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;
        PrintVTable(*((int*)&b1));
        Base2 b2;
        PrintVTable(*((int*)&b2));
        Derive d;
        PrintVTable(*((int*)&d));
        PrintVTable(*((int*)((char*)&d+sizeof(Base1))));
    
    }
    

    这里写图片描述

    菱形虚拟继承

    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));
    
    }

    菱形虚拟继承对象模型如下图所示:

    这里写图片描述

    在菱形虚拟继承中:这里既有虚函数表,又有虚基表,要理解,就需要在编译代码的时候自己看一下内存中的具体情况。如图,可以看出,在菱形虚拟继承中,把基类的保存为公有的,这就需要用虚基表用偏移量找到他。这里注意虚函数的重写,因为看的是Derive的对象模型,所以在继承的时候,有的函数进行了重写。

  • 相关阅读:
    bzoj4326 NOIP2015 运输计划
    bzoj4293 [PA2015]Siano
    bzoj4238 电压
    bzoj4216 Pig
    bzoj 4237稻草人
    [题解] PowerOJ 1752 运输问题 (最大/小费用最大流)
    [题解] PowerOJ 1748 星际转移问题 (最大流 + 并查集)
    [题解] PowerOJ 1746 航空路线问题 (最大费用最大流)
    [题解] PowerOJ 1754 负载平衡问题 (最小费用最大流)
    [题解] PowerOJ 1753 分配问题 (最大/小费用最大流)
  • 原文地址:https://www.cnblogs.com/chan0311/p/9427327.html
Copyright © 2020-2023  润新知