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\n",VfArray);
    for(size_t i = 0;VfArray[i]!=0;++i)
    {
        printf("vfunc[%d]:0x%p\n",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的对象模型,所以在继承的时候,有的函数进行了重写。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值