This question already has answers here:
c++ virtual inheritance
(3 answers)
Closed 10 years ago.
The output of the program below is:
5
5
#include <iostream>
using namespace std;
struct A
{
public:
int myInt;
A(int n): myInt(n){}
A(): myInt(5) {}
};
class B : virtual public A
{
public:
B(int n):A(10) {}
B():A(10) {}
};
class C : virtual public A
{
public:
C(int n):A(3*n) {}
};
class D : public B, public C
{
public:
D(int n=90) : C(2*n), B(n) {}
};
class E : public D
{
public:
E(int n=20):D(n-1) {}
};
int main()
{
D d(100);
cout << d.myInt << endl;
E e;
cout << e.myInt << endl;
return 0;
}
Consider the object d. From what I understand the inheritance is constructed based on the order of the inheritance list (rather than the initialization list) so B class is constructed first with the param 100 which goes to class A with the parameter 10. So now A sets myInt to the value 10. The same goes for Class c and because myInt is virtual then it is set to the number 600. I never expected 5. why is this happening?
See article in parashift:
Because a virtual base class subobject occurs only once in an
instance, there are special rules to make sure the virtual base
class's constructor and destructor get called exactly once per
instance. The C++ rules say that virtual base classes are constructed
before all non-virtual base classes. The thing you as a programmer
need to know is this: constructors for virtual base classes anywhere
in your class's inheritance hierarchy are called by the "most derived"
class's constructor.
Related
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.
This question already has answers here:
Order of constructor call in virtual inheritance
(3 answers)
Closed 7 years ago.
I've heard that using the virtual keyword solves the diamond problem.
However, when I did this:
#include <iostream>
using namespace std;
class A {
public:
A(int x = 100) {
num = x;
}
protected:
int num;
};
class B1 : virtual public A{
public:
B1(int x = 50) : A(2*x) {
}
};
class B2 : virtual public A{
public:
B2(int x = 50) : A(2*x) {
}
};
class C : public B1, public B2 {
public:
C(int x = 75) : B1(2*x), B2(2*x) {};
int getData(){ return num; }
};
int main() {
C c(10);
cout << c.getData();
cin.get();
return 0;
}
It displays the output as 100 instead of what I expected, i.e. 40. Why?
When you use virtual inheritance, you are guaranteed to have one single instance of the common base class (cite); therefore, B1 and B2 cannot have their own instance of A, but they will share a single instance with C. For instance, if you define C's constructor as follows:
C(int x = 75) : B1(2*x), B2(2*x), A(x) {};
you'll see your code outputs 10. The key is in what #dyp has commented:
the common base class is initialized in the most derived class
(Of course in the example above it doesn't make any sense to have all B1, B2 and A in the initializer list, as having Awill suffice).
This question already has an answer here:
Why is Default constructor called in virtual inheritance?
(1 answer)
Closed 9 years ago.
C++11 standard provides a way to inherit constructors from the base class. My question is regarding earlier standards. Suppose I inherit constructors in the following way:
class Base {
public:
Base() {};
Base(int b) { a = ++b;}
virtual int foo() {return 0;}
int a;
};
class A : public virtual Base {
public:
A() {}
A(int b): Base(b) {}
int foo() {return a*a;}
};
class C : public A {
public:
C() {}
C(int b ): A(b) {}
int foo() { return (a*a + a);}
};
Note that I am having virtual inheritance of the Base class. Now when I try to initialize a pointer to an object of type C then instead of calling Base(b) constructor, the code ends up calling Base() constructor. Here is the main function that I used:
int main(){
C *c = new C(5);
std::cout << c->Base::a << std::endl;
}
The output value of "a" is 0. However, when I remove the virtual keyword while inheriting the Base class, then Base(b) constructor is called and the value of "a" is 6. Can someone help me in understanding what is going on? Why is it that with virtual inheritance default constructor is called?
Virtual base classes are initialised based on the member initialiser list of the constructor of the most derived class.
In your case, when you're creating an instance of C, its Base subobject will be initialised based on the member-initialiser list in C's constructor; and since Base is not listed there, it will be default-initialised.
If you were creating an instance of A, then indeed A's member-initialiser list would be used.
So to call the Base constructor which you want, you'd have to modify C's constructor like this:
C(int b ): A(b), Base(b) {}
This question already has answers here:
c++ virtual inheritance
(3 answers)
Closed 9 years ago.
In multiple inheritance, I have a virtual Base class which is inherited by class A and class B. A and B are base classes of AB. Please see the code below.
In constructor of A and B, Base(string) constructor is called. I am expecting to get following output:
Base::Base(std::string)
A::A()
B::B()
But I am getting following output:
Base::Base()
A::A()
B::B()
Why default constructor of Base is being called?
#include<iostream>
#include<string>
using namespace std;
class Base{
public:
Base(){
cout<<__PRETTY_FUNCTION__<<endl;
}
Base(string n):name(n){
cout<<__PRETTY_FUNCTION__<<endl;
}
private:
string name;
};
class A : public virtual Base {
public:
A():Base("A"){
cout<<__PRETTY_FUNCTION__<<endl;
}
private:
string name;
};
class B : public virtual Base {
public:
B():Base("B"){
cout<<__PRETTY_FUNCTION__<<endl;
}
private:
string name;
};
class AB : public A, public B{
};
int main(){
AB a;
}
The virtual base is constructed by the most-derived object. So AB's constructor call the Base constructor, but since you didn't specify a constructor for AB, its default constructor just calls the default constructor of Base.
You could call the string-constructor from AB like this:
struct AB : A, B
{
AB() : Base("hello"), A(), B() { }
};
Note that the constructors A::A() and B:B() do not call the Base constructor in this setup!
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
gcc c++ virtual inheritance problem
Hi all,
I'm wondering about how the compiler would handle different initialization values when using multiple inheritance from a virtual base class. Consider the notorious 'diamond of dread' inheritance scheme:
Base
/ \
/ \
D1 D2
\ /
\ /
Join
In order to avoid having two copies of Base in Join, I use virtual inheritance for D1 and D2 (see e.g. here). Now, lets say Base is not abstract, but has a member field, which is initialized in its constructor:
class Base {
public:
Base(int x_) {x = x_;};
virtual ~Base(){};
public:
int x;
};
class D1 : public virtual Base {
public:
D1() : Base(1) {};
virtual ~D1(){};
};
class D2 : public virtual Base {
public:
D2() : Base(2) {};
virtual ~D2(){};
};
class Join : public D1, public D2 {
public:
Join(){};
~Join(){};
};
int main()
{
Join j;
cout << j.x << endl;
return 0;
}
Will the output be 1, 2, or is it compiler-dependent?
It shoudn't compile. Virtual bases are initialized by the most derived class which is Join. Join doesn't explicitly initialize Base but Base has no accessible default constructor.
[It also won't compiler because definitions of classes need to be terminated with a ; but I've assumed that this is a typo. main should also return int and I've assumed that j.x is a typo for j->x.]
When you have virtual inheritance it is the final class that must initialise the virtual base class.
Therefore the constructor of Join must construct Base:
class Join : public D1, public D2
{
public:
Join() : Base(3){} // or whatever value
~Join(){}
};
It is the exception to the rule that classes only normally initialise their immediate base-classes.
(Aside from that main should return int and you would need to do j->x not j.x as j is a pointer, as well as the fact you must delete it as you called new)
Since the Base does not have an implicit constructor and both C1 and C2 are virtual bases, you would have to change it like this (and also add semicolons after the rest of the class declarations as pointed out by Charles Bailey)
class Join : public D1, public D2 {
public:
Join() : Base(3) {};
~Join(){};
};
int main()
{
Join j;
cout << j.x << endl;
}
Then it would print 3 to the standard output