views:

1582

answers:

7

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

I know what it means, but what steps can I take to avoid it?

+11  A: 

virtual inheritance. That's what it's there for.

eduffy
Where in the inheritance hierarchy?
ilitirit
If you have B and C derived from A, and D derived from B and C, then B and C must both declare A as a virtual base. Specifically, each instance of virtual inheritance of the same class is collapsed into one class. Any non-virtual ones will not be collapsed, causing the diamond to recur.
coppro
imho, that's a solution to the problem, but not a way to avoid it...
Chris M.
While virtual inheritence is the feature for getting around the Diamond of Death problem, I think that there are better ways to work around the problem. Namely, inheriting from abstract base classes (interface classes) instead of inheriting from multiple concrete classes.
Nick Haddad
+10  A: 

I'd stick to using multiple inheritance of interfaces only. While multiple inheritance of classes is attractive sometimes, it can also be confusing and painful if you rely on it regularly.

Bob Somers
+1  A: 

Well, the great thing about the Dreaded Diamond is that it's an error when it occurs. The best way to avoid is to figure out your inheritance structure beforehand. For instance, one project I work on has Viewers and Editors. Editors are logical subclasses of Viewers, but since all Viewers are subclasses - TextViewer, ImageViewer, etc., Editor does not derive from Viewer, thus allowing the final TextEditor, ImageEditor classes to avoid the diamond.

In cases where the diamond is not avoidable, using virtual inheritance. The biggest caveat, however, with virtual bases, is that the constructor for the virtual base must be called by the most derived class, meaning that a class that derives virtually has no control over the constructor parameters. Also, the presence of a virtual base tends to incur a performance/space penalty on casting through the chain, though I don't believe there is much of a penalty for more beyond the first.

Plus, you can always use the diamond if you are explicit about which base you want to use. Sometimes it's the only way.

coppro
A: 

I would suggest a better class design. I'm sure there are some problems that are solved best through multiple inheritance, but check to see if there is another way first.

If not, use virtual functions/interfaces.

+3  A: 

A practical example:

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

Notice how class D inherits from both B & C. But both B & C inherit from A. That will result in 2 copies of the class A being included in the vtable.

To solve this, we need virtual inheritance. It's class A that needs to be virtually inherited. So, this will fix the issue:

class A {};
class B : virtual public A {};
class C : virtual public A {};
class D : public B, public C {};
Mark Ingram
That's only avoiding A being twice in memory, it does not avoid any problems caused by the Diamond. See http://tinyurl.com/abtjcb ; how do you implement getDepartment, that it always returns the right thing? You can't! Your design is flawed. See http://tinyurl.com/ccjnk6
Mecki
That's what scope is for. Alternatively you can use the "using" statement in class D.
Mark Ingram
A: 

Inheritance is a strong, strong weapon. Use it only when you really need it. In the past, diamond inheritance was a sign that I was going to far with classification, saying that a user is an "employee" but they are also a "widget listener", but also a ...

In these cases, it's easy to hit multiple inheritance issues.

I solved them by using composition and pointers back to the owner:

Before:

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

After:

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

     WidgetListener listener;
     LectureAttendee attendee;
};

Yes, access rights are different, but if you can get away with such an approach, without duplicating code, it's better because it's less powerful. (You can save the power for when you have no alternative.)

A: 

This link will answer your question in detail :

http://www.parashift.com/c++-faq-lite/multiple-inheritance.html

VJo