多重继承的二义性以及解决方法

//多重继承的二义性以及解决方法
//学习目的:了解类的继承原理及多重继承二义性的解决方法。
/*

//本程序代码来源《MFC权威剖析》p68
*/

第一种多重继承的二义性
class Employee
{
public:
 char Name[40];
 bool Sex;
};
class Worker : public Employee
{
};
class Manager : public Employee
{
};
class Engineer : public Worker, public Manager
{
};
//Engineer的实例化对象内存中包含两个Employee子对象,分别属于Worker和Manager子对象,
//这样在该实例的内部就封装了两套员工个人档案,显然是错误的。
{
 Engineer eng;
 eng.Worker::Sex = true;
 eng.Manager::Sex = false;//eng的性别即使男又是女
}
/解决办法
//在父类存在共同双亲的情况下,可以通过虚拟基类来解决。
//虚拟基类的作用是:如果在一个派生类的继承结构中,存在两个同样的虚拟基类,那么
//该类的实例化对象内存中只存在一个虚拟基类的子对象。
//事例
class Employee
{
public:
 char Name[40];
 bool Sex;
};
class Worker : public virtual Employee  //Employee
{
};
class Manager : public virtual Employee  //Employee
{
};
class Engineer : public Worker, public Manager
{
};
//这样的继承方式,虚拟基类的子对象不再包含在每个父类中,而是单独存在。
//父类对象中存在一个指向其虚拟父类子对象的一个指针,该指针被称为虚父类指针,
//由编译器生成。这样就保证了在多重继承时,子类实例中只存在一个虚拟基类的子对象。
//但同名的非虚拟基类的子对象没有被合并。

/第二种多重继承的二义性
class ParentA
{
public:
 void fun() {printf("%d\n", m_Value); };
private:
 int m_Value;
};
class ParentB
{
public:
 void fun() {printf("%d\n", m_Value); };
private:
 int m_Value;
};
class Son : public ParentA, public ParentB
{
};
///解决办法
//在父类没有共同双亲的情况下,一般在子类中将名字冲突的成员重新定义,
//以此解决二义性。

/使用虚拟基类需要注意的问题

[html]  view plain  copy
  1. #include "stdio.h"  
  2. class Base  
  3. {  
  4. public:  
  5.  Base(){printf("Base is constructed  as default\n");}  
  6.  Base(int i)   
  7.  {   
  8.   m_iValue=i;  
  9.   printf("Base is constructed  in constructing list\n");  
  10.  }  
  11.  ~Base(){printf("Base is deconstructed\n");}  
  12.    
  13.  int GetiValue()const  
  14.  {   
  15.   return m_iValue;   
  16.  }  
  17. private:  
  18.  int m_iValue;  
  19. };  
  20. class ParentA :public virtual Base  
  21. {  
  22. public:  
  23.  ParentA(){}  
  24.  ParentA(int i,float f):Base(i)  
  25.  { m_fValue=f; }  
  26.  float GetfValue()const  
  27.  {   
  28.   return m_fValue;   
  29.  }  
  30. private:  
  31.  float m_fValue;  
  32. };  
  33. class ParentB :public virtual Base  
  34. {  
  35. public:  
  36.  ParentB(){}  
  37.  ParentB(int i,char c):Base(i)  
  38.  { m_cValue=c; }  
  39.    
  40.  char GetcValue()const  
  41.  {   
  42.   return m_cValue;   
  43.  }  
  44. private:  
  45.  char m_cValue;  
  46. };  
  47. class Son:public ParentA,public ParentB  
  48. {  
  49. public:  
  50.  Son(int i,float f,char c):ParentA(i,f),ParentB(i,c)  
  51.  { }  
  52.  void Output()  
  53.  {  
  54.   printf("son member is %d  %8.2f  %c\n",  
  55.    GetiValue(),GetfValue(),GetcValue());  
  56.  }  
  57. };  
  58.   
  59. int main(int argc, char* argv[])  
  60. {  
  61.  Son son(6,92.33,'D');  
  62.  son.Output();    
  63.  return 0;  
  64. }  
  65. /*输出  
  66. Base is constructed  as default  
  67. son member is -858993460     92.33  D  
  68. ase is deconstructed  
  69. */  
  70. //由程序输出可以看出,虚拟基类只被构造一次,销毁一次,所以只存在一个子对象。  
  71. //但Base基类被调用的是默认构造函数,ParentA和ParentB对虚拟基类的构造无效。  
  72. //其实,为了保证虚拟基类只被构造一次,虚拟基类的构造函数不能按照传统的方式调用,  
  73. //即不能被直接子类调用,而是由当前最底层次类的构造函数调用,该类被称为最派生类。  
  74. //道理其实很简单,和虚函数原理是一样的。  
  75. //如果将Son的构造函数改成:  
  76. Son(int i, float f, char c):ParentA(i, f),ParentB(i, c),Base(i){}  
  77. /*则输出  
  78. Base is constructed  as default  
  79. son member is 6     92.33  D  
  80. ase is deconstructed  
  81. */  



//应用虚拟基类虽然解决了基类子对象重复问题,但还不能完全消除二义性的可能。
//如果两个直接父类同时定义了同名的函数,则还会产生二义性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值