Search code examples
c++inheritancemultiple-inheritance

Constructor definition with virtual multiple inheritance


I think an example would describe my problem the best.

struct Base {
    Base() = delete;
    Base(int x) : x(x) {}
    int x;
};

struct Derived1 :  virtual Base {
    Derived1(int y) : Base(5), y(y) {}
    int y;
};

struct Derived2 :  virtual Base {
    Derived2(int z) : Base(10), z(z) {}
    int z;
};

struct Derived3: Derived1, Derived2 {
public:
    Derived3(int y, int z) : Derived1(y), Derived2(z) {}

};

And an error I get: In constructor ‘Derived3::Derived3(int, int)’: error: use of deleted function ‘Base::Base()’ Derived3(int y, int z) : Derived1(y), Derived2(z) {}

I do not understand why this error occurs. In my opinion all base classes are actually get initialized in this example via their constructors (explicitly Derived1 and Derived2 and implicitly Base through Derived2 (I am not sure here, maybe through Derived1)). Well, let's do what compiler tells me.

struct Derived3: Derived1, Derived2 {
public:
    Derived3(int y, int z) : Base(-1), Derived1(y), Derived2(z) {}

};

It compiles and if I do now this:

Derived3 d = Derived3(7, 9);
std::cout << d.x << std::endl;
std::cout << d.y << std::endl;
std::cout << d.z << std::endl;

I get -1, 7, 9. And it is not what I wanted at all. An idea was to initialize base class with one of its derived classes and I was expecting the first number to be 5 or 10.

So, here is my question: Why I am forced to explicitly call Base constructor when It is already done in one of the derived classes?

More specifically, as I have multiple inheritance and virtual inheritance, I believe that any instance of Derived3 has exactly one copy of instance of Base class. And I was expecting that this copy of Base is initialized in the most derived class of it (Derived1 or Derived2), but as I clearly can see it does not work in this way =( Where am I wrong?


Solution

  • When you use virtual inheritance, there is only 1 copy of Base. Who should initialize that copy, Derived 1 or Derived 2? There is no way to know. That is why you are forced to do it yourself in Derived 3, so there can be no ambiguity. That is also why you get the output you get instead of 5 or 10.

    Without virtual inheritance both Derived 1 and Derived 2 would have their own copies of Base that they would be responsible for, therefore there is no ambiguity. When you force them to inherit from the same base Derived 3 has to take ownership of Base in order to resolve the ambiguities... virtual inheritance is weird at best.