Search code examples
c++inheritancemultiple-inheritancevirtual-inheritancediamond-problem

Inheriting from multiple/diamond Inheritance


i have the following scenario:

class A
{
  public:
    A(std::string id);
};

class B : public virtual A
{
  public:
    B();
};

class C : public virtual A
{
  public:
    C();
};

class D : public B, public C
{
  public:
    D(std::string id);
};


D::D(std::string id) : A(id), B(), C()
{
}


class X : public D
{
  public:
    X(std::string id);
}

X::X(std::string id) : D(id)
{
}

Now, if i create an instance of D everything works fine. However if i create an instance of X i get a compiler error which tells me that something tries to call the default constructor of A - which does not exist. If i create it, it compiles but only the default constructor is called and accordingly, id is not correctly set/initialized.

This can be fixed by implementing the constructor of X like so:

X::X(std::string id) : A(id), D(id)
{
}

But my understanding is, that this should be unnecessary. So where's my error ?


Solution

  • You need to make all your constructors public and define a default constructor for A because the string constructor will mark the default constructor as =delete. Furthermore, the most derived class will initialize any virtual base class, quoting from the draft Standard:

    12.6.2 Initializing bases and members [class.base.init]

    10 In a non-delegating constructor, initialization proceeds in the following order: — First, and only for the constructor of the most derived class (1.8), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.

    In this case that means that X must indeed initalize A.

    #include <iostream>
    #include <string>
    
    class A
    {
    public:
      A() { std::cout << "A\n"; }
      A(std::string id) { std::cout << id << " A(id)\n"; }
    };
    
    class B : public virtual A
    {
    public:
       B() { std::cout << "B\n"; }
    };
    
    class C : public virtual A
    {
    public:
       C() { std::cout << "C\n"; }
    };
    
    class D : public B, public C
    {
    public:  
       D(std::string id): A(id) { std::cout << id << " D(id)\n"; }
    };
    
    
    class X : public D
    {
    public:
      X(std::string id): A(id), D(id) { std::cout << id << " X(id)\n"; }
    };
    
    int main()
    {
       X x("bla");
       x;       
    }