How can I avoid the Diamond of Death when using multiple inheritance?

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

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


Solution 1:

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 {};

Solution 2:

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

Solution 3:

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.

Solution 4:

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.)

Solution 5:

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

In this the attributes of Class A repeated twice in Class D which makes more memory usage... So to save memory we make a virtual attribute for all inherited attributes of class A which are stored in a Vtable.