多重继承 数据共享

本文探讨了C++中虚拟继承的概念及其实现原理。通过具体代码示例,解释了如何使用虚拟继承解决多继承带来的数据成员重复问题,从而避免二义性并节省内存。

class CFurniture
{
public:
 CFurniture(): m_iWeith( 3){ cout <<"construction of CFurniture/n";}

 void SetWidth( int iWeight)
 {
  m_iWeith= iWeight;
 }
 void GetWidth(  )
 {
  cout << m_iWeith << endl;
 }

protected:
 int m_iWeith;
};


class CBed : virtual public CFurniture //
{
public:
 void SetWidth( int iWeight)
 {
  m_iWeith= iWeight;
 }
  
};

class CSofa : virtual public CFurniture //
{
public:
 void SetWidth( int iWeight) //如果CBed和CSofa都用虚拟继承,则CBed和CSofa不能同时有该方法(即至少一个加注释)
 {
  m_iWeith= iWeight;
 }
  
};

class CSofaBed: public CSofa, public CBed
{
public:
 void SetWidth( int iWeight)//如果是虚继承,则会调用此处,不会调用基类的该函数;如果此段函数注释,则会调用基类的函数.
 {
  m_iWeith= iWeight;
 }
  
};

int _tmain(int argc, _TCHAR* argv[])
{
 CSofaBed mySB;
 mySB.SetWidth( 10);//用虚拟继承,则调用基类的该方法;如果CSofaBed类中重载了SetWidth(),则调用CSofaBed类中重载的SetWidth().即自己重载了,则调用自己的;如果没有重载,则调用虚拟继承的基类的函数
 mySB.GetWidth( );

 system("pause");
 return 0;
}
注:
(1)用虚拟继承,基类CFurniture的构造函数只被调用一次.而不用虚拟继承,则会调用二次CFurniture的构造函数.
(2)不用虚拟继承,则会出现二个对象的变量m_iWeith(CBed和CSofa各一个),故编译器不知道调用哪个,基类CFurniture的构造函数也会调用二次;而如果用虚拟继承,相当于共享数据,即相当于只有一个m_iWeith,且基类CFurniture的构造函数只会调用一次.

------------------------------------------------------------------
网上摘录:
为了解决从不同途径继承来的同名的数据成员在内存中有不同的拷贝造成数据不一致问题,将共同基类设置为虚基类。这时从不同的路径继承过来的同名数据成员在内存中就只有一个拷贝,同一个函数名也只有一个映射。这样不仅就解决了二义性问题,也节省了内存,避免了数据不一致的问题。
 class 派生类名:virtual 继承方式  基类名
virtual是关键字,声明该基类为派生类的虚基类。
在多继承情况下,虚基类关键字的作用范围和继承方式关键字相同,只对紧跟其后的基类起作用。
声明了虚基类之后,虚基类在进一步派生过程中始终和派生类一起,维护同一个基类子对象的拷贝。


对于如下的继承关系。class   a{   public:   int   i;};   class   b:public   a{};   class   c:public   a{};   class   d:public   b,public   c{};上述的继承体系中,由于类b和类c都是一般的继承于a,所以在b、c两个类对象中,都会有其基类a的数据i的一份拷贝。也就是int   b::i和   int   c::i,而此时类d继承于b和c,所以,类d中就会有两份i的数据,一份继承与b而来,另一份继承于c而来,所以对于d来说,这是冗余的,如果类b和c都是virtual   public   a的话,那么在类d中,就只有一份数据。而且无论以后怎么继承,a都只有一份。
其实虚拟继承的实现因编译器不同而不同,基本上都是用virtual   base指针来实现的,只是这个指针的位置放在哪个地方而异。


默认继承:
base   base
 |        |
 |        |
Mid1   Mid2
 |        |
  |     |
   Child
存在两个类体系是出错的原因.

虚拟继承:
   base
  |     |
 |       |
Mid1   Mid2
 |      |
  |    |
  Child
使用虚拟继承将类的体系整合起来.

### C++ 多重继承与重复继承的概念及实现细节 #### 1. 多重继承概述 多重继承是指一个派生类可以从多个基类继承特性的一种机制。在这种情况下,派生类不仅能够访问来自各个基类的成员函数和数据成员,还可能面临一些特殊的挑战,比如二义性和内存布局问题[^1]。 #### 2. 钻石型多重继承及其问题 钻石型多重继承是一种典型的多重继承场景,其中两个或更多中间层的类都从同一个顶层基类继承而来,而最终的一个派生类又同时继承自这两个中间层类。如果不加以控制,这种结构可能导致同一份基类的数据被多次实例化,从而浪费资源并引起逻辑混乱[^5]。 ##### 性能负担分析 - **额外的内存消耗**: 每次通过非虚拟方式继承都会创建一个新的基类副本。 - **非直接访问导致的消耗**: 访问共享祖先的方法变得复杂且低效。 - **初始化复杂度增加**: 正确设置所有层次关系变得更加困难[^1]。 #### 3. 虚拟继承作为解决方案 为了避免上述提到的问题,特别是防止重复继承带来的冗余拷贝现象,C++提供了虚拟继承的功能。当声明某个基类为虚基类时,即使该基类被间接地多次继承,实际只会保留一份它的实体存在于最底层的对象之中[^3]。 以下是一个简单的例子展示了如何运用虚拟继承解决问题: ```cpp // 定义公共祖父级类 class GrandParent { public: void grandMethod() {} }; // 子代A从GrandParent以常规模式继承 class ChildA : public GrandParent {}; // 子代B同样正常继承自GrandParent class ChildB : public GrandParent {}; // 后裔试图双重继承自ChildA和ChildB class Descendant : public ChildA, public ChildB {}; ``` 在这个设计下,Descendant实际上包含了两份独立的GrandParent成员,这通常不是期望的结果。改用虚拟继承后情况有所改善: ```cpp // 修改后的版本采用虚拟继承减少重复 class VirtualChildA : virtual public GrandParent {}; class VirtualChildB : virtual public GrandParent {}; class ImprovedDescendant : public VirtualChildA, public VirtualChildB {}; ``` 现在ImprovedDescendant只持有一个唯一的GrandParent实例[^4]。 #### 4. 构造函数调用顺序 在涉及多重继承的情况下,构造函数按照特定顺序执行: 1. 所有虚基类按声明顺序构建; 2. 然后是非虚直接基类依序建立; 3. 最后才是当前类自己的构造部分得以施行[^2]。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值