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

Moeb picture Moeb · Apr 17, 2010 · Viewed 78.3k times · Source
class A                     { public: void eat(){ cout<<"A";} }; 
class B: virtual public A   { public: void eat(){ cout<<"B";} }; 
class C: virtual public A   { public: void eat(){ cout<<"C";} }; 
class D: public         B,C { public: void eat(){ cout<<"D";} }; 

int main(){ 
    A *a = new D(); 
    a->eat(); 
} 

I understand the diamond problem, and above piece of code does not have that problem.

How exactly does virtual inheritance solve the problem?

What I understand: When I say A *a = new D();, the compiler wants to know if an object of type D can be assigned to a pointer of type A, but it has two paths that it can follow, but cannot decide by itself.

So, how does virtual inheritance resolve the issue (help compiler take the decision)?

Answer

Brian R. Bondy picture Brian R. Bondy · Apr 17, 2010

You want: (Achievable with virtual inheritance)

  A  
 / \  
B   C  
 \ /  
  D 

And not: (What happens without virtual inheritance)

A   A  
|   |
B   C  
 \ /  
  D 

Virtual inheritance means that there will be only 1 instance of the base A class not 2.

Your type D would have 2 vtable pointers (you can see them in the first diagram), one for B and one for C who virtually inherit A. D's object size is increased because it stores 2 pointers now; however there is only one A now.

So B::A and C::A are the same and so there can be no ambiguous calls from D. If you don't use virtual inheritance you have the second diagram above. And any call to a member of A then becomes ambiguous and you need to specify which path you want to take.

Wikipedia has another good rundown and example here