C++ 虚继承 虚基类 多继承 详细解读

首先要说一下多继承,虚基类和虚继承都是在多继承的一种情况下存在的内容。

多继承是子类继承自多个父类的继承方式。

但是在多继承的过程中,存在这样一种情况,一个基类A分别被中间基类B、C继承,然后D又继承了B、C,此时就出现了问题

?如果子类D使用父类B或者父类C独有的成员变量,这时没有问题。但是如果D使用的是A的成员变量,编译器就不知道使用的B继承自A的还是C继承自A的,产生了一个语义模糊的概念(aimbiguous的错误)。

注:成员函数是可以被多继承的而不产生上述问题,因为函数是在编译阶段就已经生成了内存的,不需要像成员变量一样之后还会有更改。

这时候,就一定要引入虚继承的概念来避语义的模糊,让B、C类虚继承自A,那么A的成员变量在D中只会保留一份,所以取消了语义模糊冲突(具体在内存中为什么会这样我还得在思考思考)。

意味着虚继承是一种简介继承的模式,对虚继承的子类本身没有问题,只对该子类的子孙(具体是再往下继承一层还是多层需要实验)有影响。

#include <iostream>

using namespace std;

class A {
protected:
    int A_a;
};

class B : public A {
protected:
    int B_b;
};

class C : public A {
protected:
    int C_c;
};

class D : public B, public C {
protected:
    int D_d;
public:

    // 此时就出现了问题,编译器不知道调用的a是继承自B的还是继承自C的,所以会产生模棱两可的情况即ambiguous,此时就要引出超级无敌的虚继承!!!
    //void A_func () {A_a = 1;}

    void B_func () {B_b = 2;}
    void C_func () {C_c = 3;}
    void D_func () {D_d = 4;}
};


////////////////////////////////////////////////////////////////////////////////////
class I {
protected:
    int i;
public:
    void setI (int i) {
        this->i = i;
    }

    int retI () {
        return i;
    }

    void specialA () {
        cout << "funcA " << endl;
    }
};

class J : virtual public I {
protected:
    int j;
    public:

        void setI (int i) {
            this->i = i;
        }

    int retI () {
        return i;
    }
};

class K : virtual public I {
protected:
    int k;
public:
    int retI () {
        return i;
    }
};
class H : public J, public K {
protected:
    int H;
public:
    void funcA () {i = 1;}
    void funcB () {j = 2;}

    void funcC () {k = 3;}

    void funcD () {H = 4;}

    const void SetI (int i) {this->i = i;}
    const int  retI () {return i;}
};
////////////////////////////////////////////////////////////////////////////////////


int main ()
{
    // 在菱形继承&虚继承中,如果一个中间类改变了虚基类中的一个成员变量继承下来的值,那么这个虚基类的成员变量的值是否被改变呢,那么这个中间类的兄弟类的相同成员变量的值被改变了吗
    I i;
    J j;
    K k;
    H h;

    cout << "I: " << i.retI () << endl;
    cout << "J: " << j.retI () << endl;
    cout << "K: " << k.retI () << endl;
    cout << "H: " << h.retI () << endl;
    cout << "可以看到此时所有的I都是未初始化的状态,但是所指向的内存却不同" << endl;
    i.setI (1);
    cout << "将I中的i设置为1之后:" << endl;
    cout << "I: " << i.retI () << endl;
    cout << "J: " << j.retI () << endl;
    cout << "K: " << k.retI () << endl;
    cout << "H: " << h.retI () << endl;
    j.setI (2);
    cout << "将J中的i设置为2之后:" << endl;
    cout << "I: " << i.retI () << endl;
    cout << "J: " << j.retI () << endl;
    cout << "K: " << k.retI () << endl;
    cout << "H: " << h.retI () << endl;
    k.setI (3);
    cout << "将K中的i设置为3之后:" << endl;
    cout << "I: " << i.retI () << endl;
    cout << "J: " << j.retI () << endl;
    cout << "K: " << k.retI () << endl;
    cout << "H: " << h.retI () << endl;
    h.setI (4);
    cout << "将H中的i设置为4之后:" << endl;
    cout << "I: " << i.retI () << endl;
    cout << "J: " << j.retI () << endl;
    cout << "K: " << k.retI () << endl;
    cout << "H: " << h.retI () << endl;

    h.specialA ();

    // 由此可见,虚继承中不同的类并不是共享内存的,应该是在类似于虚函数表的地方表示虚继承前后的变量

    return 0;
}

ps:问题?1.虚继承在一开始出现的时候就是为了解决上述问题的吗?

2.虚继承只能用来解决这一个问题吗,还可以应用在哪些场景呢?

发布了88 篇原创文章 · 获赞 9 · 访问量 7683
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览