errorman

不积跬步,无以至千里

导航

虚继承

Posted on 2023-03-27 19:55  Clemens  阅读(18)  评论(0编辑  收藏  举报

多继承产生的冲突

当存在多基类时,看下面这个例子:

class A
{
protected:
    int a;
};
class B : public A
{
protected:
    int b;
};
class C : public A
{
protected:
    int c;
};
class D : public B, public C
{
public:
    void setA(int a) {this->a = a;}
    void setB(int b) {this->b = b;}
    void setC(int c) {this->c = c;}
};
int main()
{
    D d;
}

编译会报错:

error: non-static member 'a' found in multiple base-class subobjects of type 'A':
    class D -> class B -> class A
    class D -> class C -> class A

编译器不知道成员变量a是来自B 还是来自C。

这是一个菱形继承的问题:

 

为了消除这个问题,我们可以用的一个方法是在变量面前指定具体哪个类。

void setA(int a) {this->B::a = a;}

int main()
{
    D d;
    d.setA(9);
    std::cout << d.B::a << std::endl; // 输出:9
}

当存在这种菱形继承的时候,类D拥有两套类A的成员数据,虽然可以通过添加限定符进行独立访问,但是也同样存储了两份数据占用了两份空间

可以查看内存空间:

 

使用虚继承可以解决菱形继承问题。

 

虚继承

虚继承 是面向对象编程中的一种技术,是指一个指定的基类,在继承体系结构中,将其成员数据实例共享给也从这个基类型直接或间接派生的其它类。

我们做出修改使类B 和类C 虚继承自类A:

class A
{
public:
    int a;
};

class B : public virtual A
{
public:
    int b;
};

class C : public virtual A
{
public:
    int c;
};

class D : public B, public C
{
public:
    void setA(int a) { this->a = a; }
    void setB(int b) { this->b = b; }
    void setC(int c) { this->c = c; }
};

int main()
{
    D d;
    d.setA(9);
    std::cout << d.a << std::endl;
}

我们看一下内存结构:

可以看出,实际上类D 只保留了一份类A的数据成员a。此时,类A就被成为虚基类,用来解决菱形继承带来的命名冲突和数据冗余问题。