C++菱形继承问题

在C++中,什么叫做菱形继承问题(也可以叫钻石问题),怎么避免它?

假设我们有类B和类C,它们都继承了相同的类A。另外我们还有类D,类D通过多重继承机制继承了类B和类C。因为上述图表的形状类似于钻石(或者菱形),因此这个问题被形象地称为钻石问题(菱形继承问题)。现在,我们将上面的图表翻译成具体的代码:

#include<iostream>

class Animal{
private:
    int weight;
public:
    virtual int getWeight()
    {
        return this->weight;
    }
};

class Tiger :  public Animal{};

class Lion : public Animal{};

class Liger : public Tiger, public Lion{};

int main()
{
    Liger lg;
    lg.getWeight();
}

在我们的继承结构中,我们可以看出Tiger和Lion类都继承自Animal基类。所以问题是:因为Liger多重继承了Tiger和Lion类,因此Liger类会有两份Animal类的成员(数据和方法),Liger对象"lg"会包含Animal基类的两个子对象。

所以,你会问Liger对象有两个Animal基类的子对象会出现什么问题?再看看上面的代码-调用"lg.getWeight()"将会导致一个编译错误。这是因为编译器并不知道是调用Tiger类的getWeight()还是调用Lion类的getWeight()。所以,调用getWeight方法是不明确的,因此不能通过编译。

解决方法一:

使用虚继承,C++会保证对于每个Liger对象,只有一个Animal类的子对象会被创建。

#include<iostream>

class Animal{
private:
    int weight;
public:
    virtual int getWeight()
    {
        return this->weight;
    }
};

class Tiger : virtual public Animal{};

class Lion : virtual public Animal{};

class Liger : public Tiger, public Lion{};

int main()
{
    Liger lg;
    lg.getWeight();
}

解决方法二:

指定域

#include<iostream>

class Animal{
private:
    int weight;
public:
    virtual int getWeight()
    {
        return this->weight;
    }
};

class Tiger : public Animal{};

class Lion : public Animal{};

class Liger : public Tiger, public Lion{};

int main()
{
    Liger lg;
    lg.Lion::getWeight();
}

当存在多继承时,虽然我们尽可能地保证不同类中地成员变量和成员函数命名不冲突,但是想菱形继承仍有可能发生。

所以我们应该尽可能少地使用多继承,只有在比较简单或者实在有必要时才使用,能用单一继承解决的问题就不要使用多继承。也正是这个原因,C++之后的很多面向对象的语言,例如Java、C#、PHP等,都不支持多继承。

 

参考链接:

1. https://blog.csdn.net/tounaobun/article/details/8443228

2. https://blog.csdn.net/zhanghow/article/details/53587460

posted @ 2020-04-17 19:41  Rogn  阅读(1555)  评论(0编辑  收藏  举报