Consider:
#include <iostream>
using namespace std;
class A {// base class
private:
int data;
public:
A(int data = 0)
{
this->data = data;
}
void show()
{
cout << data << endl;
return;
}
};
class B : virtual public A {
public:
B(int data = 0) :
A(data) {
}
};
class C : virtual public A {
public:
C(int data = 0) :
A(data) {
}
};
class D : public B, public C {
public:
D(int dataB = 0, int dataC = 0) :
B(dataB),
C(dataC) {
}
};
int main() {
D d(1, 2);
d.B::show();
d.C::show();
return 0;
}
The above code is the diamond class inheritance diagram. The base class is A. I use virtual inheritance to avoid the diamond problem. But why is the output of this program 0,0, not 1,2 as I expect?
B's constructor is passed data=1, and in its initializer list it calls A with data. C's constructor similar is passed data=2 and its initializer list it calls A with data.
We then ask the B and C subobjects to show their value. And we get 0 0 not 1 2 as I expect.
When you have this scheme with virtual inheritance, it is up to the most derived class in the hierarchy (in this case D) to call the constructor of the common base (A)1,2.
Since your constructor for A has a default parameter data = 0, it can be used as a default constructor. And this is what's happening, the common A sub-object gets default constructed, since you omitted it from D's member initialization list.
If you remove the default value for data, you'll get a nice compiler error for emphasis:
A(int data)
{
this->data = data;
}
On g++ it results with:
main.cpp: In constructor 'D::D(int, int)':
main.cpp:37:16: error: no matching function for call to 'A::A()'
C(dataC) {
1 Remember that with virtual inheritance there is only one sub-object of type A. And both the B and C sub-objects refer to it. It is impossible for your calls to show to print different things, since they access the same data. That is why it's up to the most derived class, so there is no ambiguity.
[class.mi/4]
A base class specifier that does not contain the keyword virtual specifies a non-virtual base class. A base class specifier that contains the keyword virtual specifies a virtual base class. For each distinct occurrence of a non-virtual base class in the class lattice of the most derived class, the most derived object shall contain a corresponding distinct base class subobject of that type. For each distinct base class that is specified virtual, the most derived object shall contain a single base class subobject of that type.
[class.base.init/13.1]
In a non-delegating constructor, initialization proceeds in the following order:
First, and only for the constructor of the most derived class, 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.
...
2 So if you want to construct A with specific data you'd define D::D() like this instead:
D(int dataA = 0) :
A(dataA) {
}
When you have virtual inheritance, the virtual base class is initialized by the constructor of the most derived class.
D(int dataB = 0, int dataC = 0) :
B(dataB),
C(dataC) {}
is equivalent to:
D(int dataB = 0, int dataC = 0) :
A(),
B(dataB),
C(dataC) {}
which is, in your case, the same as
D(int dataB = 0, int dataC = 0) :
A(0),
B(dataB),
C(dataC) {}
Unless you construct an instance of B,
B(int data = 0) :
A(data) {
}
is the same as
B(int data = 0) {}
with no code to initialize A since A is already initialized in the constructor of D.
Same thing applies to the implementation of C::C(int data).
That explains the output you are seeing.
I think you misunderstood the concept of virtual inheritance and the 'diamond problem'. With virtual inheritance, you create a diamond inheritance pattern, but from your post, it appears that you want to avoid that and instead have two bases A, one from B and another from C. To obtain that, simply avoid virtual inheritance in B and C, when your code will write 1 2.
Incidently, if only B has virtual inheritance from A but C conventional inheritance from A, then D will have two bases A, but that from B is again default initialised (as explained in the other answers).
Related
I read the following piece of code somewhere, as an example to solve the diamond problem in case of multiple inheritance :
#include<iostream>
using namespace std;
class A
{
int x;
public:
A() {}
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(100) { }
};
int main()
{
D d;
d.print();
return 0;
}
Suppose class D is defined as follows :
class D: public B, public C
{
public:
D():B(),C(){}
};
I get some garbage value in the print. And if the class D is defined as follows (parameterized constructor for A is explicitly called) :
class D: public B, public C
{
public:
D():B(),C(),A(20){}
};
I get 20 as output. In the first case, I can understand that the default A() constructor is called, hence the garbage value as x is not set to any value.
However, in the second case, its not clear. When is the parameterized constructor for A(int) is called? If I understood correctly, call order depends on order of inheritance. Since B is inherited first, B's constructor call takes precedence over C.Since B inherits A, A() will be called first, of all. Then B's constructor will be called. Then C's constructor will be called. At last, A(int) will be called, as A's constructor is called explicitly in class D. If this is the case, then the output is well justified for the second case. However, this, then contradicts the output for the below piece of code :
#include<iostream>
using namespace std;
class Person {
public:
Person(int x) { cout << "Person::Person(int ) called" << endl; }
Person() { cout << "Person::Person() called" << endl; }
};
class Faculty : virtual public Person {
public:
Faculty(int x):Person(x) {
cout<<"Faculty::Faculty(int ) called"<< endl;
}
};
class Student : virtual public Person {
public:
Student(int x):Person(x) {
cout<<"Student::Student(int ) called"<< endl;
}
};
class TA : public Faculty, public Student {
public:
TA(int x):Student(x), Faculty(x), Person(x) {
cout<<"TA::TA(int ) called"<< endl;
}
};
int main() {
TA ta1(30);
}
The output for this program :
Person::Person(int ) called
Faculty::Faculty(int ) called
Student::Student(int ) called
TA::TA(int ) called
Why Person(int) called at the beginning in this case, and not at the last?
N4594 12.6.2/13:
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 .
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).
Then, non-static data members are initialized in the order they were declared in the class definition
(again regardless of the order of the mem-initializers).
Finally, the compound-statement of the constructor body is executed.
[ Note: The declaration order is mandated to ensure that base and member subobjects are destroyed in the
reverse order of initialization. —end note ]
Construction always starts from the base class. If there are multiple base classes then, it starts from the left most base. (side note: If there is a virtual inheritance then it's given higher preference). Then it comes the turn for member fields. They are initialized in the order they are declared. At the last the class itself is constructed.
The order of destructor is exactly reverse
Since B inherits A, A() will be called first, of all. Then B's
constructor will be called.
This is not quite true when A is virtually inherited.
When a class is virtually inherited, it is effectively inherited by the most derived class, for the purpose of invoking constructors and destructors. That's what virtual inheritance between.
Since D derives from B and C, in that class hierarchy D inherits A when it comes to invoking constructors and destructors, because D is the most-derived class.
With virtual inheritance, constructor of the virtual class is called only in the most derived class.
And order of initialization doesn't depend of order of initialization list, but to the order of declaration inside the class.
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.
In the following code the Multi Path Inheritance was resolved by using Virtual Class
How did the constructor work?
A Constructor cannot be inherited or virtual or static.
/*Multi Path Inheritance*/
class A{
public:
int a;
A(){
a=50;
}
};
class B:virtual public A{
public:
/*B(){
a = 40;
}*/
};
class C:virtual public A{
public:
/*C(){
a = 30;
}*/
};
class E:virtual public A{
public:
E(){
a = 40;
}
};
class D : public B, public C, public E{
public:
D(){
cout<<"The value of a is : "<<a<<endl;
}
};
int main(int argc, char *argv[]){
D d;
return 0;
}
Base on following quota from standard 12.6.2/10, so the constructor body will be called in following orde: A->B->C->D, so the final value of a will be 40.
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.
— 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).
You can find a lot of informations and examples about virtual inheritance here (yes, it's actually on msdn, how strange :) )
As for the constructors, constructors get called as you specify them. If you don't specify a call for a virtua-base class constructor,
constructors for virtual base classes anywhere in your class's
inheritance hierarchy are called by the "most derived" class's
constructor.
(read it here).
#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?
I am using a class say baseClass, from which I derive another class derivedClass. I have a problem definition that says, apart from others:
i) A member - object initialiser should be used to initialise a data member, say var1, that is declared in the base class.
ii) i) is done inside a base class constructor. It says, this has to be invoked only via a derived class constructor.
iii) The base class is an abstract class, whose objects cannot be created. But, I have a third class, inside which, I use:
baseClass *baseObjects[5];
The compiler does not report an error.
I do not understand, what i) and ii) really mean. An explanation in simple words would be fine. Also, any assistance on iii) is welcome.
Question 1:
Read about constructors : http://www.cprogramming.com/tutorial/constructor_destructor_ordering.html
Question 2:
Read about initialization list:
http://www.cprogramming.com/tutorial/initialization-lists-c++.html
Question 3:
Read about pointers to derived class:
http://www.learncpp.com/cpp-tutorial/121-pointers-and-references-to-the-base-class-of-derived-objects/
I think this way instead of just answering your question you could understand what's going on,
I think an illustration will be best.
i)
class A
{
int i;
public:
A(int ii) : i(ii) {}
}
The part i(ii) is an example of a member - object initialiser. Since C++ guarantees all constructors of members will be called before the constructor body is entered, this is your only way of specifying which constructor to call for each member.
ii) In C++ there is no super keyword. You must specify the base class as such:
class B : public A
{
public:
B(int i) : A(i) {}
}
That's partially due to the fact C++ allows multiple inheritence.
iii) Note that you haven't created any objects, only pointers to objects. And it's by this method polymorphism via inheritence is acheived in C++.
#include <iostream>
class Base
{
public:
Base(int i)
{}
virtual ~Base() = 0
{}
protected:
int i_;
};
class Derived: public Base
{
public:
Derived(int i, int j) : Base(i), j_(j)
{}
private:
int j_;
};
int main(int argc, char* argv[])
{
//Base b(1); object of abstract class is not allowed
Derived d(1, 2); // this is fine
}
As you can see i_ is being initalized by the Derived class by calling the Base class constructor. The = 0 on the destructor assures that the Base class is pure virtual and therefore we cannot instantiate it (see comment in main).
i) The following is what is known as an initializer list, you can use initializer lists to make sure that the data members have values before the constructor is entered. So in the following example, a has value 10 before you enter the constructor.
Class baseClass
{
int a;
public:
baseClass(int x):a(x)
{
}
}
ii) This is how you would explicitly call a base class constructor from a derived class constructor.
Class derivedClass : public baseClass
{
int a;
public:
derivedClass(int x):baseClass(x)
{
}
}
iii) You can't directly create instances of an abstract class. However, you can create pointers to an abstract base class and have those pointers point to any of its concrete implementations. So if you have an abstract base class Bird and concrete implementations Parrot and Sparrow then Bird* bird could point to either a Parrot or Sparrow instance since they are both birds.