Why is constructor of a grand parent deleted in this case? - c++

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 {
^

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) {}
};

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.

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.

Related

Inherited templated class constructor definition problem (deep copy with pointers to base class) [duplicate]

Why can't I do this?
class A
{
public:
int a, b;
};
class B : public A
{
B() : A(), a(0), b(0)
{
}
};
You can't initialize a and b in B because they are not members of B. They are members of A, therefore only A can initialize them. You can make them public, then do assignment in B, but that is not a recommended option since it would destroy encapsulation. Instead, create a constructor in A to allow B (or any subclass of A) to initialize them:
class A
{
protected:
A(int a, int b) : a(a), b(b) {} // Accessible to derived classes
// Change "protected" to "public" to allow others to instantiate A.
private:
int a, b; // Keep these variables private in A
};
class B : public A
{
public:
B() : A(0, 0) // Calls A's constructor, initializing a and b in A to 0.
{
}
};
Leaving aside the fact that they are private, since a and b are members of A, they are meant to be initialized by A's constructors, not by some other class's constructors (derived or not).
Try:
class A
{
int a, b;
protected: // or public:
A(int a, int b): a(a), b(b) {}
};
class B : public A
{
B() : A(0, 0) {}
};
Somehow, no one listed the simplest way:
class A
{
public:
int a, b;
};
class B : public A
{
B()
{
a = 0;
b = 0;
}
};
You can't access base members in the initializer list, but the constructor itself, just as any other member method, may access public and protected members of the base class.
# include<stdio.h>
# include<iostream>
# include<conio.h>
using namespace std;
class Base{
public:
Base(int i, float f, double d): i(i), f(f), d(d)
{
}
virtual void Show()=0;
protected:
int i;
float f;
double d;
};
class Derived: public Base{
public:
Derived(int i, float f, double d): Base( i, f, d)
{
}
void Show()
{
cout<< "int i = "<<i<<endl<<"float f = "<<f<<endl <<"double d = "<<d<<endl;
}
};
int main(){
Base * b = new Derived(10, 1.2, 3.89);
b->Show();
return 0;
}
It's a working example in case you want to initialize the Base class data members present in the Derived class object, whereas you want to push these values interfacing via Derived class constructor call.
Why can't you do it? Because the language doesn't allow you to initializa a base class' members in the derived class' initializer list.
How can you get this done? Like this:
class A
{
public:
A(int a, int b) : a_(a), b_(b) {};
int a_, b_;
};
class B : public A
{
public:
B() : A(0,0)
{
}
};
While this is usefull in rare cases (if that was not the case, the language would've allowed it directly), take a look at the Base from Member idiom. It's not a code free solution, you'd have to add an extra layer of inheritance, but it gets the job done. To avoid boilerplate code you could use boost's implementation
Aggregate classes, like A in your example(*), must have their members public, and have no user-defined constructors. They are intialized with initializer list, e.g. A a {0,0}; or in your case B() : A({0,0}){}. The members of base aggregate class cannot be individually initialized in the constructor of the derived class.
(*) To be precise, as it was correctly mentioned, original class A is not an aggregate due to private non-static members

Unable to create a parameterized constructor using inheritance,"Is not a nonstatic data member or base class of class" [duplicate]

Why can't I do this?
class A
{
public:
int a, b;
};
class B : public A
{
B() : A(), a(0), b(0)
{
}
};
You can't initialize a and b in B because they are not members of B. They are members of A, therefore only A can initialize them. You can make them public, then do assignment in B, but that is not a recommended option since it would destroy encapsulation. Instead, create a constructor in A to allow B (or any subclass of A) to initialize them:
class A
{
protected:
A(int a, int b) : a(a), b(b) {} // Accessible to derived classes
// Change "protected" to "public" to allow others to instantiate A.
private:
int a, b; // Keep these variables private in A
};
class B : public A
{
public:
B() : A(0, 0) // Calls A's constructor, initializing a and b in A to 0.
{
}
};
Leaving aside the fact that they are private, since a and b are members of A, they are meant to be initialized by A's constructors, not by some other class's constructors (derived or not).
Try:
class A
{
int a, b;
protected: // or public:
A(int a, int b): a(a), b(b) {}
};
class B : public A
{
B() : A(0, 0) {}
};
Somehow, no one listed the simplest way:
class A
{
public:
int a, b;
};
class B : public A
{
B()
{
a = 0;
b = 0;
}
};
You can't access base members in the initializer list, but the constructor itself, just as any other member method, may access public and protected members of the base class.
# include<stdio.h>
# include<iostream>
# include<conio.h>
using namespace std;
class Base{
public:
Base(int i, float f, double d): i(i), f(f), d(d)
{
}
virtual void Show()=0;
protected:
int i;
float f;
double d;
};
class Derived: public Base{
public:
Derived(int i, float f, double d): Base( i, f, d)
{
}
void Show()
{
cout<< "int i = "<<i<<endl<<"float f = "<<f<<endl <<"double d = "<<d<<endl;
}
};
int main(){
Base * b = new Derived(10, 1.2, 3.89);
b->Show();
return 0;
}
It's a working example in case you want to initialize the Base class data members present in the Derived class object, whereas you want to push these values interfacing via Derived class constructor call.
Why can't you do it? Because the language doesn't allow you to initializa a base class' members in the derived class' initializer list.
How can you get this done? Like this:
class A
{
public:
A(int a, int b) : a_(a), b_(b) {};
int a_, b_;
};
class B : public A
{
public:
B() : A(0,0)
{
}
};
While this is usefull in rare cases (if that was not the case, the language would've allowed it directly), take a look at the Base from Member idiom. It's not a code free solution, you'd have to add an extra layer of inheritance, but it gets the job done. To avoid boilerplate code you could use boost's implementation
Aggregate classes, like A in your example(*), must have their members public, and have no user-defined constructors. They are intialized with initializer list, e.g. A a {0,0}; or in your case B() : A({0,0}){}. The members of base aggregate class cannot be individually initialized in the constructor of the derived class.
(*) To be precise, as it was correctly mentioned, original class A is not an aggregate due to private non-static members

Confusion about initializers in C++ derived classes [duplicate]

Why can't I do this?
class A
{
public:
int a, b;
};
class B : public A
{
B() : A(), a(0), b(0)
{
}
};
You can't initialize a and b in B because they are not members of B. They are members of A, therefore only A can initialize them. You can make them public, then do assignment in B, but that is not a recommended option since it would destroy encapsulation. Instead, create a constructor in A to allow B (or any subclass of A) to initialize them:
class A
{
protected:
A(int a, int b) : a(a), b(b) {} // Accessible to derived classes
// Change "protected" to "public" to allow others to instantiate A.
private:
int a, b; // Keep these variables private in A
};
class B : public A
{
public:
B() : A(0, 0) // Calls A's constructor, initializing a and b in A to 0.
{
}
};
Leaving aside the fact that they are private, since a and b are members of A, they are meant to be initialized by A's constructors, not by some other class's constructors (derived or not).
Try:
class A
{
int a, b;
protected: // or public:
A(int a, int b): a(a), b(b) {}
};
class B : public A
{
B() : A(0, 0) {}
};
Somehow, no one listed the simplest way:
class A
{
public:
int a, b;
};
class B : public A
{
B()
{
a = 0;
b = 0;
}
};
You can't access base members in the initializer list, but the constructor itself, just as any other member method, may access public and protected members of the base class.
# include<stdio.h>
# include<iostream>
# include<conio.h>
using namespace std;
class Base{
public:
Base(int i, float f, double d): i(i), f(f), d(d)
{
}
virtual void Show()=0;
protected:
int i;
float f;
double d;
};
class Derived: public Base{
public:
Derived(int i, float f, double d): Base( i, f, d)
{
}
void Show()
{
cout<< "int i = "<<i<<endl<<"float f = "<<f<<endl <<"double d = "<<d<<endl;
}
};
int main(){
Base * b = new Derived(10, 1.2, 3.89);
b->Show();
return 0;
}
It's a working example in case you want to initialize the Base class data members present in the Derived class object, whereas you want to push these values interfacing via Derived class constructor call.
Why can't you do it? Because the language doesn't allow you to initializa a base class' members in the derived class' initializer list.
How can you get this done? Like this:
class A
{
public:
A(int a, int b) : a_(a), b_(b) {};
int a_, b_;
};
class B : public A
{
public:
B() : A(0,0)
{
}
};
While this is usefull in rare cases (if that was not the case, the language would've allowed it directly), take a look at the Base from Member idiom. It's not a code free solution, you'd have to add an extra layer of inheritance, but it gets the job done. To avoid boilerplate code you could use boost's implementation
Aggregate classes, like A in your example(*), must have their members public, and have no user-defined constructors. They are intialized with initializer list, e.g. A a {0,0}; or in your case B() : A({0,0}){}. The members of base aggregate class cannot be individually initialized in the constructor of the derived class.
(*) To be precise, as it was correctly mentioned, original class A is not an aggregate due to private non-static members

Why output is showing errors

This is a code fro diamond tree problem of multiple inheritance
and according to me this code is cool but it is showing some error on compilation
..help me to figure the error
#include<iostream>
using namespace std;
class A //A Diamond tree problem
{
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(20) { }
};
class D: public B, public C{
};
int main()
{
D d;
d.print();
return 0;
}
It would be useful to see the error:
In constructor ‘D::D()’:
error: no matching function for call to ‘A::A()’
When using virtual inheritance, the virtual base class must be initialised by the most derived class. In this case, that is D; so in order to be able to instantiate D, it must initialise A:
class D: public B, public C
{
public:
D():A(42) {}
};
Alternatively, you could provide A with a default constructor. Declaring any constructor will prevent the compiler from implicitly generating one for you.
You need to provide default construct for D and call A in member initialize list:
class D: public B, public C{
public:
D():A(30){}
};
Or you could provide a default A constructor
A():x(0) {}

derive problem about c++

Why I can't access base class A's a member in class B initialization list?
class A
{
public:
explicit A(int a1):a(a1)
{
}
explicit A()
{
}
public:
int a;
public:
virtual int GetA()
{
return a;
}
};
class B : public A
{
public:
explicit B(int a1):a(a1) // wrong!, I have to write a = a1 in {}. or use A(a1)
{
}
int GetA()
{
return a+1;
}
};
class C : public A
{
public:
explicit C(int a1):a(a1)
{
}
int GetA()
{
return a-1;
}
};
A's constructor runs before B's, and, implicitly or explicitly, the former construct all of A's instance, including the a member. Therefore B cannot use a constructor on a, because that field is already constructed. The notation you're trying to use indicates exactly to use a constructor on a, and at that point it's just impossible.
To build on Alex' answer, you can initialize the base class' "a" member by controlling its construction, like so:
class B : public A
{
public:
explicit B(int a1) : A(a1) { } // This initializes your inherited "a"
...
};
Note that I'm constructing the base class (capital "A") above, rather than attempting to directly initialize its inherited member (lowercase "a", drawing from your example).
To build even further on pilcrow's answer, you could easily initialize the A member like you want by overriding it in your B class:
class B : public A
{
public:
int a; // override a
explicit B(int a1) : a(a1) // works now
{
}
...
};
Though, I wouldn't necessarily recommend this ;)