C++之钻石问题和解决方案(菱形继承问题)

翻译 2012年12月27日 14:17:10

在C++中,什么叫做钻石问题(也可以叫菱形继承问题),怎么避免它?


下面的图表可以用来解释钻石问题。






假设我们有类B和类C,它们都继承了相同的类A。另外我们还有类D,类D通过多重继承机制继承了类B和类C。因为上述图表的形状类似于钻石(或者菱形),因此这个问题被形象地称为钻石问题(菱形继承问题)。现在,我们将上面的图表翻译成具体的代码:


/*
Animal类对应于图表的类A
*/
								
class Animal { /* ... */ }; // 基类
{
int weight;

public:

int getWeight() { return weight;};

};

class Tiger : public Animal { /* ... */ };

class Lion : public Animal { /* ... */ }	
						
class Liger : public Tiger, public Lion { /* ... */ };	

在上面的代码中,我们给出了一个具体的钻石问题例子。Animal类对应于最顶层类(图表中的A),Tiger和Lion分别对应于图表的B和C,Liger类(狮虎兽,即老虎和狮子的杂交种)对应于D。

现在,问题是如果我们有这种继承结构会出现什么样的问题。

看看下面的代码后再来回答问题吧。

int main( )
{
Liger lg ;

/*编译错误,下面的代码不会被任何C++编译器通过 */

int weight = lg.getWeight();  
}


在我们的继承结构中,我们可以看出Tiger和Lion类都继承自Animal基类。所以问题是:因为Liger多重继承了Tiger和Lion类,因此Liger类会有两份Animal类的成员(数据和方法),Liger对象"lg"会包含Animal基类的两个子对象。

所以,你会问Liger对象有两个Animal基类的子对象会出现什么问题?再看看上面的代码-调用"lg.getWeight()"将会导致一个编译错误。这是因为编译器并不知道是调用Tiger类的getWeight()还是调用Lion类的getWeight()。所以,调用getWeight方法是不明确的,因此不能通过编译。


钻石问题的解决方案:


我们给出了钻石问题的解释,但是现在我们要给出一个钻石问题的解决方案。如果Lion类和Tiger类在分别继承Animal类时用virtual来标注,对于每一个Liger对象,C++会保证只有一个Animal类的子对象会被创建。看看下面的代码:

class Tiger : virtual public Animal { /* ... */ };

class Lion : virtual public Animal { /* ... */ }

你可以看出唯一的变化就是我们在类Tiger和类Lion的声明中增加了"virtual"关键字。现在类Liger对象将会只有一个Animal子对象,下面的代码编译正常:

int main( )
{
Liger lg ;

/*既然我们已经在Tiger和Lion类的定义中声明了"virtual"关键字,于是下面的代码编译OK */

int weight = lg.getWeight();  
}


因为Java不支持多继承,所以不会出现菱形继承问题。但是Java可以通过接口间接实现多重继承。

Class Mule implements Horse,Donkey
{
    /* Horse和Donkey是接口*/
}


转载自:http://www.programmerinterview.com/index.php/c-cplusplus/diamond-problem/

【C++】c++单继承、多继承、菱形继承内存布局(虚函数表结构)

c++单继承、多继承、菱形继承内存布局(虚函数表结构)
  • SuLiJuan66
  • SuLiJuan66
  • 2015年10月04日 18:44
  • 2973

C++之菱形继承

当我们谈C++时,我们谈些什么?    封装,继承,多态。这是C++语言的三大特性,而每次在谈到继承时我们不可避免的要谈到一个很重要的问题——菱形继承。a.菱形继承是什么650) this.width...
  • Monamokia
  • Monamokia
  • 2016年05月30日 13:35
  • 3766

C++菱形继承及解决方法

1.何为菱形继承? 两个子类继承同一个父类,而又有子类又分别继承这两个子类,就如上图说示。 #include #include #include using names...
  • u011032846
  • u011032846
  • 2016年01月13日 11:43
  • 235

C++菱形继承和菱形虚拟继承

单继承&多继承&菱形继承 单继承:一个子类只有一个直接父类时称这个继承关系为单继承。 多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承 菱形继承(钻石继承)存在二义性和数据冗余问题。 ...
  • qq_35452533
  • qq_35452533
  • 2017年07月25日 22:52
  • 135

C++菱形继承

菱形继承:两个子类同时继承一个父类,而又有子类同时继承这两个子类 #define _CRT_SECURE_NO_WARNINGS 1 #include using namespace std; cl...
  • qq_36236006
  • qq_36236006
  • 2017年03月26日 22:25
  • 100

【C++基础之二十一】菱形继承和虚继承

菱形继承是多重继承中跑不掉的,Java拿掉了多重继承,辅之于接口。C++中虽然没有明确说明接口这种东西,但是只有纯虚函数的类可以看作Java中的接口。在多重继承中建议使用“接口”,来避免多重继承中可能...
  • jackyvincefu
  • jackyvincefu
  • 2014年01月05日 09:05
  • 10542

java接口菱形继承

其实菱形继承的副作用只是因为公共基类的成员变量 Java的接口可以做出类似菱形继承的结构,但因为公共基类(接口?)中没有成员变量,所以没有二义性问题啦 当然也可以使用内部类(嵌套类)来实现类似...
  • wenwenxiong
  • wenwenxiong
  • 2015年04月30日 18:32
  • 973

钻石继承和虚继承

在C++中,类是允许多继承的,多继承大大的提高了代码的复用、减少代码冗余、大大的提高了类的表现力,使得类更贴近现实中的事物,使用起来更为灵活,更面向对象。 但由于这灵活的语法,使得C++使用起来比别...
  • qq_26369213
  • qq_26369213
  • 2015年08月22日 21:39
  • 1284

C++ 钻石继承与虚继承

首先,何为钻石继承,顾名思义,在类的继承过程中,继承结构是一个类似菱形(钻石)的结构就属于钻石继承,如下: 这是一个最简单的钻石继承。实际上,在复杂的继承表中,只要子类按不同的继承路径回溯到基类...
  • zhu2695
  • zhu2695
  • 2013年04月15日 23:28
  • 977

virtual inheritance(解决多几继承中的diamond problem)

http://en.wikipedia.org/wiki/Virtual_inheritance
  • xunileida
  • xunileida
  • 2012年03月30日 21:53
  • 369
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++之钻石问题和解决方案(菱形继承问题)
举报原因:
原因补充:

(最多只允许输入30个字)