Search code examples
c++inheritanceconstructorcompiler-errorsmultiple-inheritance

c++ multiple inheritance and explicit constructor calls


Consider we have a parent class A that has protected members x and y and a constructor:

A::A(int xpos, int ypos) : x(xpos), y(ypos) {}

Now consider we have two classes B and C that inherit from A and have constructors as defined below.

class B : public virtual A
B::B(int xpos, int ypos) : A(xpos,ypos) {}

class C : public virtual A
C::C(int xpos, int ypos) : A(xpos,ypos) {}    

Finally let's have a class D that inherits both B and C.

class D : public B, public C

If I write Ds constructor as follows I get a compile error saying that Ds constructor must explicitly call As constructor.

D::D(int xpos, int ypos) : B(xpos,ypos), C(xpos,ypos) {}  

Why is this? Surely this is problematic if I attempt to inherit from classes that I don't know anything about the classes constructor? Isn't it enough that B and C both explicitly call As constructor?


Solution

  • It is not enough that both B and C explicitly call A's constructor, because A is inherited "virtually". This means that the content of a single instance of A is "shared" between B and C.

    If C++ were to allow B or C to initialize the "shared" instance of A unilaterally, you could get inconsistent behavior. Consider what would happen if D's constructor switched the order of xpos and ypos in the two initializers:

    D::D(int xpos, int ypos) : B(xpos,ypos), C(ypos,xpos) {}
    

    Since both B and C forward xpos and ypos to A::A, the instance of A shared between B and C would not be initialized in a consist way. That is why D::D is required to initialize A's virtual instance explicitly.

    Note that this is required only when you deal with virtual inheritance, because a portion of B and C instances is shared.

    Surely this is problematic if I attempt to inherit from classes that I don't know anything about the classes constructor?

    The requirement to call the base-of-the-base constructor does break encapsulation. However, when you inherit classes with virtual bases, the inheritor is expected to understand not only the structure and behavior of its "sibling bases", but also the interactions among them. That is why breaking of encapsulation could be considered justified, even though it's not ideal.