20170511_请说清楚什么是菱形继承

20170511_请说清楚什么是菱形继承?

1、我们都知道C++中的三大特性——“封装、继承、多态”,但是当我们谈到“继承”时,不免会想起一个很重要的问题:菱形继承。

2、那么菱形继承是什么呢?请看图。

    

如上图所示,中间类A 和中间类B 共同继承了基类Base,而与此同时,派生类D 又同时继承了A 和B。

意思就是:多个类继承了同一个公共基类,而这些派生类又同时被一个类继承。

这时,会发生什么事情呢?请看代码。

#include<iostream>
using namespace std;
class Base
{
protected:
    int _base;
public:
    void fun()
        cout << "Base::fun" << endl;
};

class A:public Base
{
protected:
    int _a;
};

class B : public Base
{
protected:
    int _b;
};
class D :public A, public B
{
private:
    int _d;
};
int main()
{
    D d;
    d.fun();    //编译器报错:调用不明确
    return 0;
}

这时,我们可以看到,类D的对象d 中保存了两份Base 成员,一份是从中间类A 继承来的,另一份是从中间类B 继承来的。当我们想要调用从Base 继承来的fun() 函数时,就会出现编译错误——调用不明确问题,同时这也造成了数据冗余的问题——明明需要一份就可以了,我们却偏偏保存了两份。

3、那么,我们该如何解决这个问题呢?

  • 第一种方法:使用作用域运算符::

int main()
{
    D d;
    d.A::fun();
    d.B::fun();
    return 0;
}
这个做法是没有问题,但是没有从根本上解决这个问题,而且还不方便。

  • 第二种方法:使用虚继承机制


如上图所示,虚继承,也就是让中间类A 和中间类B 继承基类Base 时前面加上关键字virtual,使其成为虚继承关系。

注意:这里并不是D 使用虚继承,

那么,虚继承是如何解决这个烦人的问题呢?请看图。


此时,我们可以看到,中间类A 和中间类B 不再保存基类Base 中的具体内容了,而是保存了该基类中的具体内容的一份偏移地址,然后将基类中的数据保存在一个公共位置处,这样就实现了“去除调用不明确问题!”

再看代码:

#include<iostream>
using namespace std;
class Base
{
protected:
	int _base;
public:
	void fun()
		cout << "Base::fun" << endl;
};

class A:virtual public Base
{
protected:
	int _a;
};

class B :virtual public Base
{
protected:
	int _b;
};
class D :public A, public B
{
private:
	int _d;
};
int main()
{
	D d;
	d.fun();//调用从基类Base继承来的函数,而且该函数只有这一份。
	return 0;
}
这样的话,就既解决了数据冗余的问题,又解决了直接使用d.func() 来调用基类Base 中的func() 函数。

 4、 *虚继承和虚函数是完全不同的两个概念,希望大家不要随意搞混。

想要了解虚函数的同学可以看看另一篇博文《C++的继承&多态》。

http://zimomo.blog.51cto.com/10799874/1752936



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值