二十七、继承(四) 多重继承、虚继承与虚基类、虚基类及其派生类构造函数

一、多重继承
          在现实生活中,经常会有一个对象属于多个类别的情况,比如沙发床同时具有沙发和床的特点,这个时候我们可以使用多重继承来模拟这种关系。例子如下:
#include <iostream>
using namespace std;
class Furniture
{
public:
	Furniture(int weight) : weight_(weight)
	{
	}
	int weight_;
};
class Bed : public Furniture
{
public:
	Bed(int weight) : Furniture(weight)
	{
	}
	void Sleep()
	{
		cout<<"Sleep ..."<<endl;
	}
};
class Sofa : public Furniture
{
public:
	Sofa(int weight) : Furniture(weight)
	{
	}
	void WatchTV()
	{
		cout<<"Watch TV ..."<<endl;
	}
};

class SofaBed : public Bed, public Sofa
{
public:
	SofaBed(int weight) : Bed(weight), Sofa(weight)
	{
		FoldIn();
	}
	void FoldOut()
	{
		FoldOut ..."<<endl;
	}
	void FoldIn()
	{
		cout<<"FoldIn ..."<<endl;
	}
};

int main(void)
{
	SofaBed sofaBed(10);
	//sofaBed.weight_ = 10;
	//sofaBed.weight_ = 20;

	sofaBed.Bed::weight_ = 10;
	sofaBed.Sofa::weight_ = 20;

	sofaBed.WatchTV();
	sofaBed.FoldOut();
	sofaBed.Sleep();
	return 0;
}
在注释行中,出现了访问二义性。因为此时SofaBed有两个重量,一个继承自Sofa,一个继承自Bed。内存模型如下:

对于这个例子来说,家具应该只有一个重量,SofaBed有两个重量显然是不合理的,我们想在多继承之后只有一个重量属性,此时我们应该使用虚继承。
二、虚继承与虚基类
          为了解决从不同途径继承来的同名的数据成员在内存中有不同的拷贝造成数据不一致问题,将共同基类设置为虚基类。这时从不同的路径继承过来的同名数据成员在内存中就只有一个拷贝,同一个函数名也只有一个映射。这样不仅就解决了二义性问题,也节省了内存,避免了数据不一致的问题。也就是说虚继承 主要用来解决多继承时可能发生的对同一基类继承多次而产生的二义性问题,它 为最远的派生类提供唯一的基类成员,而不重复产生多次拷贝。
示例如下:
#include <iostream>
using namespace std;

class Furniture
{
public:
	int weight_;
};

class Bed : virtual public Furniture
{
public:
	void Sleep()
	{
		cout<<"Sleep ..."<<endl;
	}
};

class Sofa : virtual public Furniture
{
public:
	void WatchTV()
	{
		cout<<"Watch TV ..."<<endl;
	}
};

class SofaBed : public Bed, public Sofa
{
public:
	void FoldOut()
	{
		cout<<"FoldOut ..."<<endl;
	}
	void FoldIn()
	{
		cout<<"FoldIn ..."<<endl;
	}
};

int main(void)
{
	SofaBed sofaBed;
	sofaBed.weight_ = 10;
	sofaBed.WatchTV();
	sofaBed.FoldOut();
	sofaBed.Sleep();
	return 0;
}

三、虚基类及其派生类构造函数
          在虚继承中,虚继承自多个类的最远派生类是如何初始化的呢,它不能对每个基类的构造函数都调用一次,这样会导致对同一个变量多次初始化。实际上虚基类的派生类初始化具有以下规则:
  • 虚基类的成员实际上是由最远派生类的构造函数通过调用虚基类的构造函数进行初始化的。
  • 在整个继承结构中,直接或间接继承虚基类的所有派生类,都必须在构造函数的成员初始化表中给出对虚基类的构造函数的调用。如果未列出,则表示调用该虚基类的默认构造函数。
  • 在建立对象时,只有最远派生类的构造函数调用虚基类的构造函数,该派生类的其他基类对虚基类构造函数的调用被编译器忽略。
#include <iostream>
using namespace std;

class Furniture
{
public:
	Furniture(int weight) : weight_(weight)
	{
		cout<<"Furniture ..."<<endl;
	}
	~Furniture()
	{
		cout<<"~Furniture ..."<<endl;
	}
	int weight_;
};

class Bed : virtual public Furniture
{
public:
	Bed(int weight) : Furniture(weight)
	{
		cout<<"Bed ..."<<endl;
	}
	~Bed()
	{
		cout<<"~Bed ..."<<endl;
	}
	void Sleep()
	{
		cout<<"Sleep ..."<<endl;
	}

};
class Sofa : virtual public Furniture
{
public:
	Sofa(int weight) : Furniture(weight)
	{
		cout<<"Sofa ..."<<endl;
	}
	~Sofa()
	{
		cout<<"~Sofa ..."<<endl;
	}
	void WatchTV()
	{
		cout<<"Watch TV ..."<<endl;
	}
};

class SofaBed : public Bed, public Sofa
{
public:
	SofaBed(int weight) : Bed(weight), Sofa(weight), Furniture(weight)
	{
		cout<<"SofaBed ..."<<endl;
		FoldIn();
	}
	~SofaBed()
	{
		cout<<"~SofaBed ..."<<endl;
	}
	void FoldOut()
	{
		cout<<"FoldOut ..."<<endl;
	}
	void FoldIn()
	{
		cout<<"FoldIn ..."<<endl;
	}
};

int main(void)
{
	SofaBed sofaBed(5);
	sofaBed.weight_ = 10;

	sofaBed.WatchTV();
	sofaBed.FoldOut();
	sofaBed.Sleep();
	return 0;
}
运行结果:



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值