2

The compiler is complaining the constructor of D is deleted because of ill forming why ?

#include<iostream>
using namespace std;

class A
{
   int x;
   public:
   A(int i) { x = i; }
   void print() { cout << x; }
};

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

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

class D: public B, public C {
};

int main()
{
   D d;
   d.print();
   return 0;
}

Output

main.cpp:37:4: error: use of deleted function 'D::D()' D d; ^ main.cpp:32:7: note: 'D::D()' is implicitly deleted because the default definition would be ill-formed: class D: public B, public C { ^

Winter
  • 3,894
  • 7
  • 24
  • 56
Raju
  • 1,149
  • 1
  • 6
  • 19

3 Answers3

6

Due to the rules for initialization of virtual base classes,

class D: public B, public C {
};

is equivalent to:

class D: public B, public C {
    public:
       D() : A(), B(), C() {}
};

That's why you cannot create in instance of D.

Solution 1

Change A so it has a default constructor.

class A
{
     int x;
   public:
     A(int i = 0) { x = i; }
     void print() { cout << x; }
};

Solution 2

Change D to:

class D: public B, public C {
    public:
       D() : A(0), B(), C() {}
};

or a simpler version,

class D: public B, public C {
    public:
       D() : A(0) {}
};
R Sahu
  • 204,454
  • 14
  • 159
  • 270
2

That's because D inherits from A indirectly using virtual. A doesn't have a parameterless constructor so a compiler-generated constructor for D can't be made.

Hatted Rooster
  • 35,759
  • 6
  • 62
  • 122
0

Note: this is mostly just adding a reference to the standard, in case anybody might care (but as usual for him, @R. Sahu's answer is quite accurate).

The standard specifies ([class.base.init]/13) that:

In a non-delegating constructor, initialization proceeds in the following order:
(13.1) — First, and only for the constructor of the most derived class (6.6.2), 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.
(13.2) — Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).

So, since A is a virtual base class, it's initialized directly by the most derived class (D). Only afterward, the direct base classes are initialized--but for anything to compile, the most derived class must be able to initialize the virtual base class(es).

There is one point some might find interesting in a case like this. Let's modify your class structure just a tiny bit, so we to the necessary initialization, and (importantly) initialize with a unique value in each constructor:

#include <iostream>

class A {
    int i;
 public:
    A(int i) : i(i) {}

    void show() { std::cout << "value: " << i << "\n"; }
};

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

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

class D : public B, public C {
public:
    D() : A(0) {}
};

int main() {
    D d;
    d.show();
}

In this case, what exactly happens? We have three different constructors each "thinking" it's going to initialize the A object with a different value? Which one "wins"?

The answer is that the one in the most-derived constructor (D::D) is the one that' used to initialize the virtual base class object, so that's the one that "wins". When we run the code above, it should print 0.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111