http://en.wikipedia.org/wiki/Diamond_problem

我知道这意味着什么,但我可以采取哪些措施来避免它?

有帮助吗?

解决方案

一个实际的例子:

class A {};
class B : public A {};
class C : public A {};
class D : public B, public C {};

注意D类如何继承B&但是B& B都是C继承自A.这将导致类别A的2个副本包含在vtable中。

要解决这个问题,我们需要虚拟继承。它的A类需要实际上是遗传的。所以,这将解决问题:

class A {};
class B : virtual public A {};
class C : virtual public A {};
class D : public B, public C {};

其他提示

虚拟继承。这就是它的用途。

我坚持只使用接口的多重继承。虽然类的多重继承有时很有吸引力,但如果你经常依赖它,它也会让人感到困惑和痛苦。

继承是一种强大而有力的武器。只有在你真正需要时才使用它。在过去,钻石继承是我在分类方面走得很远的一个标志,说用户是“雇员”。但它们也是一个“小部件监听器”,但也是一个......

在这些情况下,很容易遇到多个继承问题。

我通过将构图和指针反馈给所有者来解决它们:

在:

class Employee : public WidgetListener, public LectureAttendee
{
public:
     Employee(int x, int y)
         WidgetListener(x), LectureAttendee(y)
     {}
};

后:

class Employee
{
public:
     Employee(int x, int y)
         : listener(this, x), attendee(this, y)
     {}

     WidgetListener listener;
     LectureAttendee attendee;
};

是的,访问权限是不同的,但如果您可以使用这种方法,而不重复代码,那就更好了,因为它不那么强大。 (当你别无选择时,你可以节省电力。)

class A {}; 
class B : public A {}; 
class C : public A {}; 
class D : public B, public C {};

在这里,A类的属性在D类中重复两次,这使得内存使用更多......所以为了节省内存,我们为存储在Vtable中的A类的所有继承属性创建了一个虚拟属性。

嗯,关于Dreaded Diamond的好处在于它发生时是一个错误。要避免的最好方法是事先弄清楚你的继承结构。例如,我工作的一个项目有观众和编辑。编辑器是Viewers的逻辑子类,但由于所有的Viewers都是子类 - TextViewer,ImageViewer等,因此编辑器不会派生自Viewer,因此允许最终的TextEditor,ImageEditor类避免钻石。

如果钻石无法避免,请使用虚拟继承。然而,对虚拟基础最大的警告是,虚拟基础的构造函数必须由最派生类调用,这意味着实际派生的类无法控制构造函数参数。此外,虚拟基地的存在往往会导致通过链条进行性能/空间惩罚,但我不认为除了第一个之外还有更多的惩罚。

另外,如果您明确要使用哪个基础,则可以随时使用钻石。有时它是唯一的方式。

我建议更好的课堂设计。我确信有一些问题可以通过多重继承得到最好的解决,但请先查看是否还有另一种方法。

如果没有,请使用虚拟功能/接口。

通过委派使用继承。然后,这两个类将指向基础A,但必须实现重定向到A的方法。它具有将A的受保护成员转换为“私有”的副作用。 B,C和D中的成员,但现在你不需要虚拟,而且你没有钻石。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top