I'm a bit confused about how virtual base classes work. In particular, I was wondering how the constructor of the base class gets called. I wrote an example to understand it:
#include <cstdio>
#include <string>
using std::string;
struct A{
string s;
A() {}
A(string t): s(t) {}
};
struct B: virtual public A{
B(): A("B"){}
};
struct C: virtual public A {};
struct D: public B, public C {};
struct E: public C, public B {};
struct F: public B {};
int main(){
D d;
printf("\"%s\"\n",d.s.c_str());
E e;
printf("\"%s\"\n",e.s.c_str());
F f;
printf("\"%s\"\n",f.s.c_str());
B b;
printf("\"%s\"\n",b.s.c_str());
}
Which outputs
""
""
""
"B"
I wasn't sure what would happen in the first two cases, but for the third one at least I was expecting the output to be "B". So now I'm just confused. What are the rules for understanding how the constructor of A gets called?
There is always just one constructor call, and always of the actual, concrete class that you instantiate. It is your responsibility to endow each derived class with a constructor which calls the base classes' constructors if and as necessary, as you did in B's constructor.
Update: Sorry for missing your main point! Thanks to ildjarn.
However, your B inherits virtually from A. According to the standard (10.1.4 in the FIDS), "for each distinct baseclass that is specified virtual, the most derived object shall contain a single base class subobject of that type". In your case this means that when constructing the base, your class F immediately calls A's default constructor, not B's.
Virtual base classes are always constructed by the most derived class.
Related
Say I have several classes that inherit like so.
#include <iostream>
struct A {
A() {std::cout << "a";}
};
struct B : A {};
struct C : A {};
struct D : B, C {};
int main {
D d;
}
On executing the program, as expected, I see two A objects were constructed, one for the B and one for the C object that are constructed when creating a D object. Whoever, how can I not create two A objects? I want the same A object to be used to create B and C objects. Is this possible?
If B and C both use virtual inheritance for A, then there will only be a single base class object for each D object:
struct B : virtual A {};
struct C : virtual A {};
//...
D d; //prints "a" rather than "aa"
Live demo
If you're looking for a non-polymorphic solution, you're out of luck. Otherwise, change to the following:
struct B : virtual A {};
struct C : virtual A {};
As written, every D object has two sub-objects of type A, one inherited from class B and one inherited from class C. So the constructor of A must run twice, once for each sub-object.
If the original design is wrong, and there should only be one A sub-object, despite the use of two bases B and C, the change is to make A a virtual base of B and a virtual base of C. That way there will only be one A sub-object in a D object, and the constructor of A will only run once when a D object is constructed.
Consider the following code:
class A {
};
class B : public A {
};
class C : public B{
public:
C() : A() {} // ERROR, A is not a direct base of B
};
In this case GCC (4.8.1, C++99) gives me the correct error (I understand this behavior):
prog.cpp:12:8: error: type āaā is not a direct base of ācā
However if the inheritance between b and a is virtual, this does not happen:
class A {
};
class B : virtual public A {
};
class C : public B{
public:
C() : A() {} // OK with virtual inheritance
};
Why does this work?
Is A now considered a direct base to C by the compiler?
In general, because this is how C++ tries to resolve the diamond inheritance problem http://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem (whether or it is a good or bad solution is left as an exercise to the reader).
All inheritance is a combination of an is-a and a has-a relationship...you must instantiate an instance of the parent. If you have the following classes:
class a;
class b : a;
class c : a;
class d : b,c;
Then you've instantiated an a for each b and c. d will not know which a to use.
C++ solves this by allowing virtual inheritance, which is high-overhead inheritance that allows b and c to share the same a if inherited in d (it is much more complicated than that, but you can read up on that on your own).
The most derived type in the chain needs to be able to override the instantiation of the shared class to control disparities in the way that the shared class is inherited in the parent classes. Take the following example:
class a {int x; public: a(int xx) {x=xx;} int get_x() {return x;}};
class b : public virtual a { public: b(): a(10){}};
class c : public virtual a { public: c(): a(15){}};
class d : public virtual b, public virtual c {public: d() : a (20) {}};
int main() {
d dd;
std::cout << dd.get_x() << std::endl;//20, d's constructor "wins"
return 0;
}
If d did not define what a was instantiated as, it would have definitions for conflicting instantiations (from b and c). C++ handles this by forcing the most derived class in the inheritance chain to instantiate all parent classes (the above would barf if d did NOT explicitly instantiate a, though if a supplied a default constructor that could be implicitly used) and ignoring all parent instantiations.
Why does this work?
According to the standard (10.1.4 in the FIDS), "for each distinct baseclass that is specified virtual, the most derived object shall contain a single base class subobject of that type".
Virtual base is shared between all classes that derive from it for the instance of the object. Since a constructor may only be called once for a given instaniation of an object, you have to explicitly call the constructor in the most derived class because the compiler doesn't know how many classes share the virtual base. This is because the compiler will start from the most base class's constructor and work to the most derived class. Classes that inherit from a virtual base class directly, will not, by the standard, call their virtual base classes constructor, so it must be called explicitly.
From N3337, 12.6.2
Initializing bases and members
In the definition of a constructor for a class, initializers for direct and virtual base subobjects and non-static data members can be specified by a ctor-initializer, which has the form
Perhaps someone who has better version of Standard can verify this.
class A: public B, public C { };
In this case order of execution is:
B(); // base(first)
C(); // base(second)
A(); // derived
class A: public B, virtual public C { };
But in this case,when i write virtual with class c while inheriting,order of
// execution becomes:
C(); // virtual base
B(); // ordinary base
A(); // derived
i have read somewhere that order of calling constructor depends on the order of declaration while inheriting multiple classes but how does the order of execution gets changed on writing virtual with a class.I am not able to get why i am getting such result.
The virtual base class constructors are always executed first according to the C++ standard. From the working draft N3242, page 272 line 10, we learn that:
Virtual base class constructors go first, in the order of a left-to-right depth-first traversal of the inheritance graph.
Direct base classes go next, in declaration order.
So the behavior you see is exactly what is required in the C++ standard. It makes sense, because the virtual base classes may show up multiple times in the inheritance and of course they can each only be constructed once. Hence there has to be an initial round of virtual base class construction, followed by the usual non-virtual base class construction.
There is also a nice explanation on this page.
If you have a virtual class as a parent, you cannot hope that initialization goes always in the order of declaration. In fact it is possible that the first (say non-virtual) parent class has itself a dependency on the virtual class. Hence in that case the virtual class must be constructed first.
I think this is the reason why C++ specification says that initializers of virtual parent classes get always executed first. As shown by #Dan Roche there is a predictable order of initialization.
Example:
class B: public A {...}
class C: public B, virtual A {...}
In this example in C's initialization it is not possible to initialize B before A since B's initialization requires A to be initialized first.
another example
This example is to show that you shouldn't rely on base class initialization order:
#include <iostream>
using namespace std;
struct A {
A() {cout<<"A()"<<endl;}
};
struct B {
B() {cout<<"B()"<<endl;}
};
struct C: virtual A, virtual B {
C() {cout<<"C()"<<endl;}
};
struct D: virtual B, virtual A, C {
D() {cout<<"D()"<<endl;}
};
int main() {
cout<<"construct C"<<endl;
new C;
cout<<"construct D"<<endl;
new D;
}
output:
construct C
A()
B()
C()
construct D
B()
A()
C()
D()
As the example shows, when C is constructed as a base class of D, the order of initialization of A and B is reversed. This means that you cannot rely on the order of initialization of virtual base classes if you want that somebody could extend your class.
if i run this code
#include<iostream>
using namespace std;
class Final;
class MakeFinal{
public:
friend class Final;
MakeFinal(){cout<<"makefinal\n";}
};
class Final: public virtual MakeFinal{
public:
Final(){cout<<"Final\n";}
};
class Derived:public Final{
public:
Derived(){cout<<"Derived\n";}
};
int main(){
//Final f;
Derived d;
return 0;
}
Output is :
makefinal
Final
Derived
But if i make MakeFinal() constructor private , compiler shows error message. What is this different constructor call hierarchy based on ?
Refer to:
C++ FAQs - virtual inheritance constructors
http://www.parashift.com/c++-faq/virtual-inheritance-ctors.html
Because of the fact that "Initialization list of most-derived-class's ctor directly invokes the virtual base class's ctor. ", your most derived needs to invoke the constructor of the virtual base directly. Therefore, for what you want to do you'd need to make the most derived class a friend too...
Furthermore, it seems that you don't understand virtual inheritance correctly. Refer to this FAQ to understand the purpose and proper use of virtual inheritance.
If your class A have private constructor, you cannot create object a of this class like that (see):
A a;
When an object b of class B that derives from A is created, base class constructor must also be called. If it is private, it cannot be called and the derived object cannot be created.
#include<iostream.h>
class A{
public:
int i;
A(int j=3):i(j){}
};
class B:virtual public A{
public:
B(int j=2):A(j){}
};
class C:virtual public A{
public:
C(int j=1):A(j){}
};
class D:public B, public C {
public:
D(int j=0):A(j), B(j+1), C(j+2){}
};
int main()
{
D d;
cout<<d.i;
return 0;
}
I am not being able to understand how the final output is zero. Every time j is initialized in default way to some fixed value, how is the value initialized in the constructor of class D being passed to class A?
Since A is a virtual base class, it should be constructed only once, so it is not possible to create it with different constructor parameters, and the C++ compiler has to choose one way of creating a base class.
The obvious question is: which one is used?
And the rule is: the one specified in the most derived class that inherits A directly.
The initialization order is simple: first A (with the parameter value from D constructor initialization list), then B (it is D's first ancestor; and it uses the instance of A created before), then C (and it shares the same A instance), finally D (and it also shares the same A object as B and C).
The rule with virtual base inheritance is:
"The most derived class in a hierarchy must construct a virtual base"
In your case, from the most derived class D You explicitly called the constructor of A by passing an argument 0 So it sets the i to 0. As mentioned in rule virtual base class is constructed through most derived class only and the other constructor calls through intermediate hierarchy have no effect since it is only constructed once.
The order of calling is:
A(int)
B(int)
C(int)
Good Read:
Why virtual base class constructors called first?