Search code examples
c++multiple-inheritancevirtual-inheritance

Multiple inheritance: usage of skipping 'virtual' keyword and refusing the diamond hierarchy?


I understand how and why do we have to use the virtual keyword to solve the "diamond problem", and create a class hierarchy like this:

   A
  / \
 /   \
B     C
 \   /
  \ /
   D

Code example:

class A { int a; public: A(int a) : a(a) {} };
class B : public virtual A { int b; public: B(int a, int b) : A(a), b(b) {} };
class C : public virtual A { int c; public: C(int a, int c) : A(a), c(c) {} };
class D : public B, public C { public: D(int a, int b, int c) : A(a), B(0, b), C(0, c) {} };

I couldn't find an answer to my question: Why do we have to tell the compiler (using the virtual keyword) that we want to create a "diamond" class hierarchy? Why does the compiler not generate it automatically? If we don't use virtual, the compiler generates the class hierarchy below:

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

Is there any programming situation where the second hierarchy is useful and works? EDIT (to make my question clear): Why did they want us to use virtual? I suppose, the reason is that they wanted to give an option to us. Any example where the second class hierarchy is the best choice to use?


Solution

  • Is there any programming situation where the second hierarchy is useful and works?

    Although there might be, that becomes a less interesting question (in my opinion) after I've answered the other one.

    Why do we have to tell the compiler (using the virtual keyword) that we want to create a "diamond" class hierarchy? Why does the compiler not generate it automatically?

    No, the compiler cannot generate it automatically. That is why you have to tell the compiler explicitly when you want inheritance to be virtual.

    Assuming such automation existed, in order for the compiler to guess that the base A of B should be virtual, it would have to know that A is also the base of C, and that B and C are both bases of D. So, the meaning of the definition of B would depend on the definition of D (which also depends on C. Essentially, all classes that are part of same hierarchy will depend in all other classes in that hierarchy, except the very top base). But some classes of the hierarchy may be defined in completely different translation units that may be compiled at a completely different time than the others. The C++ compiler simply cannot assume that it has knowledge of all classes.

    There is one approach that would make this possible: Make all inheritance virtual. However, virtual inheritance has some (small, but non-zero) overhead, so this is not an ideal solution. Also, virtual inheritance makes static_cast to derived type impossible, so such cast would require dynamic_cast which requires Run Time Type Information and there is interest in allowing limited C++ implementations that lack RTTI support.