2

With regards to the sample below, which family of structs and specific errors suffer from the Diamond Problem? The Wikipedia definition is too generic to be understood in the context of C++. In particular, virtual inheritance only solves the base class ambiguity but not function ambiguity.

struct A {void func(){}};
struct B: A {void func(){}};
struct C: A {void func(){}};
struct D: B,C {};


struct A2 {void func(){}};
struct B2: virtual A2 {void func(){}};
struct C2: virtual A2 {void func(){}};
struct D2: B2,C2 {};

struct A3 {virtual void func(){}};
struct B3: virtual A3 {void func(){}};
struct C3: virtual A3 {void func(){}};
struct D3: B3,C3 { }; // not ok: func must be overriden

struct A4 {virtual void func(){}};
struct B4:  A4 {void func(){}};
struct C4:  A4 {void func(){}};
struct D4: B4,C4 { }; // not ok: func must be overriden

int main()
{

  A*a = new D; // not ok: ambiguous base A

  A2*a2 = new D2; // ok

  A3*a3 = new D3; // ok

  A4*a4 = new D4; // not ok: ambiguous base A

  D d;
  d.func(); // not ok: ambiguous: candidates are A::func, B::func, C::func

  D2 d2;
  d2.func(); // not ok: ambiguous: B2::func, C2::func 

  D3 d3;
  d3.func(); // not ok: ambiguous: B3::func, C3::func 

  D4 d4;
  d4.func(); // not ok: ambiguous: A4::func, B4::func, C4::func 

}

2 Answers2

1

The diamond problem is not specific to C++, it is a more general problem in multiple inheritance. It is not a problem per se, it is just something that you have to be careful about.

Say you have this:

    A
    ^
   / \
  |   |
  B   C
  ^   ^
   \ /
    D

The problem is that can be interpreted in two different ways:

  • any B is a A (until then ok nothing special)
  • any C is a A (also ok)
  • any D is a B (beware)
  • any D is a C (beware)

For the two last point by transitivity you can then say:

  • any D is A (because any B is a A)
  • any D is A (because any C is a A)

And then: is a D twice a A or only once? That's the diamond problem.

Now take A has Person, B as BusinessMan, C as SportMan and D as SportAndBusinessMan, you can agree that a SportAndBusinessMan is a Person (not twice a Person), he has two arms, two legs, not four.

But sometimes you want to use that diagram to duplicate the inherited attributes. In such a case you would have wanted to say : four legs, etc.

Then as usual C++ didn't make a choice and let you chose what you want. If you want the first case this is virtual inheritance, in the second the traditional inheritance. Virtual inheritance means you inherit only once from above.

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

A D is a A and inherit its attributes only once.

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

A D is a A and inherits its attributes twice, inheriting once from B and one from C, thus twice. And then you naturally have an ambiguity, are you talking about a inherited from B or from C.

You have to distinguish in between relations between types and inheritance tree path.

Jean-Baptiste Yunès
  • 34,548
  • 4
  • 48
  • 69
0

The comments in your code do a good job of answering the first part of your question.

How does virtual inheritance solve the "diamond" (multiple inheritance) ambiguity?

For your function ambiguity, we have virtual functions and override keyword in C++

Ardent Coder
  • 3,777
  • 9
  • 27
  • 53