欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

c++多态对象模型:有虚函数的菱形继承和菱形虚拟继承

程序员文章站 2024-03-22 23:48:04
...
    -

一:菱形继承

class A
{
public:
    virtual void func1()
    {
        cout << "A::func1()";
    }

    virtual void func2()
    {
        cout << "A::func2()";
    }
public://这里为public,方便待会赋值查看内存
    int _a;
};

class B : public A
{
public:
    virtual void func1()
    {
        cout << "B::func1()";
    }

    virtual void func3()
    {
        cout << "B::func3()";
    }
public:
    int _b;
};

class C : public A
{
public:
    virtual void func1()
    {
        cout << "C::func1()";
    }

    virtual void func3()
    {
        cout << "C::func3()";
    }
public:
    int _c;
};

class D : public B, public C
{
public:
    virtual void func1()
    {
        cout << "D::func1()";
    }

    virtual void func4()
    {
        cout << "D::func4()";
    }
public:
    int _d;
};

它的结构是这样的:
c++多态对象模型:有虚函数的菱形继承和菱形虚拟继承
来看他的布局:

void test()
{
    D d;
    d.B::_a = 1;
    d._b = 2;
    d.C::_a = 3;
    d._c = 4;
    d._d = 5;
}

c++多态对象模型:有虚函数的菱形继承和菱形虚拟继承
可以看出,B继承了A,B里有A的虚表,C里有A的虚表,然后D继承了B和C,那么D里有两个虚表。
c++多态对象模型:有虚函数的菱形继承和菱形虚拟继承
接下来打印地址:
Print((int**)(((int*)&d)));//第一个虚表
c++多态对象模型:有虚函数的菱形继承和菱形虚拟继承
可以看到,func4依然是给了第一个虚表。

注:因为清理解决方案导致地址不同,不影响。

这样得到了菱形继承的模型:
c++多态对象模型:有虚函数的菱形继承和菱形虚拟继承

二:菱形虚拟继承

class A
{
public:
    virtual void func1()
    {
        cout << "A::func1()";
    }

    virtual void func2()
    {
        cout << "A::func2()";
    }
public:
    int _a;
};

class B : virtual public A//虚拟继承
{
public:
    virtual void func1()
    {
        cout << "B::func1()";
    }

    virtual void func3()
    {
        cout << "B::func3()";
    }
public:
    int _b;
};

class C : virtual public A//虚拟继承
{
public:
    virtual void func1()
    {
        cout << "C::func1()";
    }

    virtual void func3()
    {
        cout << "C::func3()";
    }
public:
    int _c;
};

class D : public B, public C
{
public:
    virtual void func1()
    {
        cout << "D::func1()";
    }

    virtual void func4()
    {
        cout << "D::func4()";
    }
public:
    int _d;
};

结构变化不大,就是多了虚拟继承,那么再来看看布局:

void test()
{
    D d1;
    d1.B::_a = 1;
    d1._b = 2;
    d1.C::_a = 3;
    d1._c = 4;
    d1._d = 5;
}

c++多态对象模型:有虚函数的菱形继承和菱形虚拟继承
好像看不出来什么,好复杂的感觉。
来看内存:
c++多态对象模型:有虚函数的菱形继承和菱形虚拟继承
因为已经对数据成员赋值,所以看的能清楚一些,蓝色框起来的三个是属于B,桔色框起来三个属于C,紫色框起来三个属于A,接下来我用到打印函数。


    Print((int**)(*((int**)&d1)));
    Print((int**)(*((int**)((char*)&d1 + 12))));
    Print((int**)(*((int**)(    (char*)&d1+28   ))));

c++多态对象模型:有虚函数的菱形继承和菱形虚拟继承
可以看到,B的虚表存了B的func3和D的func4,C的虚表存了C的func3,A的虚表存了D的func1和A的func2。
之前有文章写了菱形继承,虚拟继承解决了二义性和数据冗余,由于D同时继承了B和C,B和C又分别继承了A,所以D里面会有两份A,所以加上虚拟继承,A会在最下面。
至于虚机表指针:

c++多态对象模型:有虚函数的菱形继承和菱形虚拟继承
c++多态对象模型:有虚函数的菱形继承和菱形虚拟继承
这里分别是B和C的虚机表,第一行是-4的意思,表示和虚表的地址差4字节,若没有虚表存在,就会存0。
(ff ff ff ff是-1,顺着推也能得到ff ff ff fc是-4)
第二行是距离A的步数,B离A24字节,C离A12字节。
所以得到了对象模型:
c++多态对象模型:有虚函数的菱形继承和菱形虚拟继承