I have tried to find a lot that what if only one class is made virtual in multiple inheritance?
The behaviour of constructor call is not clear to me in this case.
Let say for example code-
#include<iostream>
using namespace std;
class grand{
public:
grand(){cout<<"grandfather"<<endl;}
};
class parent1:virtual public grand{ //virtual used only here
public:
parent1(){cout<<"parent1 "<<endl;}
};
class parent2: public grand{
public:
parent2(){cout<<"parent2"<<endl;}
};
class child:public parent1,public parent2{
public:
child(){cout<<"child"<<endl;}
};
int main() {
child s;
return 0;
}
The output of this code comes as
grandfather
parent1
grandfather
parent2
child
but in above code if we change this
class parent1:virtual public grand{
public:
parent1(){cout<<"parent1 "<<endl;}
};
class parent2: public grand{
public:
parent2(){cout<<"parent2"<<endl;}
};
to this
class parent1:public grand{ //virtual removed from here
public:
parent1(){cout<<"parent1 "<<endl;}
};
class parent2:virtual public grand{ //virtual is added here
public:
parent2(){cout<<"parent2"<<endl;}
};
output is shown as
grandfather
grandfather //why parent1 constructor is not called here?
parent1
parent2
child
My concern is why parent1 constructor is not called after grandfather?
The standard says [C++11 section 12.6.2/10] that :
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.
— 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.
So your virtual base classes are always built first... This is really important in the case of virtual base class sharing.
Related
I have tried to find a lot that what if only one class is made virtual in multiple inheritance?
The behaviour of constructor call is not clear to me in this case.
Let say for example code-
#include<iostream>
using namespace std;
class grand{
public:
grand(){cout<<"grandfather"<<endl;}
};
class parent1:virtual public grand{ //virtual used only here
public:
parent1(){cout<<"parent1 "<<endl;}
};
class parent2: public grand{
public:
parent2(){cout<<"parent2"<<endl;}
};
class child:public parent1,public parent2{
public:
child(){cout<<"child"<<endl;}
};
int main() {
child s;
return 0;
}
The output of this code comes as
grandfather
parent1
grandfather
parent2
child
but in above code if we change this
class parent1:virtual public grand{
public:
parent1(){cout<<"parent1 "<<endl;}
};
class parent2: public grand{
public:
parent2(){cout<<"parent2"<<endl;}
};
to this
class parent1:public grand{ //virtual removed from here
public:
parent1(){cout<<"parent1 "<<endl;}
};
class parent2:virtual public grand{ //virtual is added here
public:
parent2(){cout<<"parent2"<<endl;}
};
output is shown as
grandfather
grandfather //why parent1 constructor is not called here?
parent1
parent2
child
My concern is why parent1 constructor is not called after grandfather?
The standard says [C++11 section 12.6.2/10] that :
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.
— 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.
So your virtual base classes are always built first... This is really important in the case of virtual base class sharing.
How can I inherit a constructor from Grandpa(Non-Direct Base) to Son? For example:
class Grandpa
{
public:
Grandpa();
~Grandpa();
};
class Dad : public Grandpa
{
public:
Dad();
~Dad();
};
class Son : public Dad
{
public:
using Grandpa::Grandpa;
~Son();
};
ERROR: "can only inherit constructor from direct base"
There is a way how to make it work?
There is no way to inherit a non-direct base class' constructor. However, you can still use it. If you want to pass a value to Grandpa's constructor from Son's constructor, you can do something like this;
class Grandpa
{
public:
Grandpa(string surname){
// some codes in the constructor
}
~Grandpa();
};
class Dad : public Grandpa
{
public:
Dad(string surname) : Grandpa(surname){};
~Dad();
};
class Son : public Dad
{
public:
Son(string surname) : Dad(surname){};
~Son();
};
Here what we do is simply, passing the value from Son's constructor to Dad's constructor, and it is just propagating to the Grandpa's constructor.
The relation of non virtual inheritance is just as direct and strong as membership: a class constructor absolutely controls the invocation of the constructors of its members and the invocation of the constructors of its direct non virtual bases. When a class is written, the way its members and direct non virtual bases is specified in the source code; changing that could invalidate a fundamental invariant of the class.
Using a non virtual base constructor directly from a further derived class would break the C++ model.
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.
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).
Related: Does "virtual base class in the case of multilevel inheritance" have significance
I have a template class that can be inherited from in order to impart some select functionality. However, it wants to prevent any classes from further inheriting from anything that inherits it.
The following seems to achieve this:
template<typename Child>
class SealingClass
{
public:
/*public methods etc*/
private:
SealingClass() {}
friend Child;
};
//simplify a bit:
#define Seal( x ) public virtual SealingClass< x >
Now, I can inherit from the above class, as follows:
class NewClass: Seal(NewClass) {};
And if I then try inheriting again from NewClass, as in:
class AnotherClass: public NewClass {};
and then make an instance of said class:
AnotherClass a;
I get the desired error, regarding the constructor in SealingClass being private.
So, everything works as I'd like!
However, I have noticed that if I remove the virtual keyword from the define..
#define Seal( x ) public SealingClass< x >
..my instantiation of AnotherClass now works just fine.
I understand that the virtual keyword, in this context, means that only one instance of the base class is defined in cases of multiple inheritance (eg diamond inheritance) where multiple instances of it could exist, leading to ambiguous function calls etc.
But, why does it affect the functionality of the above?
Thanks :)
If use virtual inheritance, the most-derived type has to do the initialization of this virtual base class. If you don't use virtual inheritance, the directly derived type has to do the initialization.
Therefore, the private ctor does not prevent the derived type NewClass from initializing the direct base class SealingClass, and AnotherClass does not have to initialize NewClass if it's not been virtually inherited.
Some examples:
template<typename Child>
class SealingClass {
public: // for now
SealingClass() {}
};
class NewClass : public SealingClass<T> {
public:
NewClass() : SealingClass<T>() {} // allowed, SealingClass<T> is a
// direct base class
};
class AnotherClass : public NewClass {
public:
AnotherClass() : NewClass() {} // allowed, NewClass is a
// direct base class
AnotherClass() : SealingClass<T>() {} // not allowed, SealingClass<T> is
// no direct nor a virtual base class
};
class NewClass_v : public virtual SealingClass<T> {
public:
NewClass_v() : SealingClass<T>() {} // allowed, SealingClass<T> is a
// direct base class
};
class AnotherClass_v : public NewClass_v {
public:
AnotherClass_v() : NewClass_v() {} // allowed, NewClass_virt is a
// direct base class
AnotherClass_v() : SealingClass<T>() {} // allowed, SealingClass<T> is a
// virtual base class
};
Now, if the ctor of SealingClass is private, AnotherClass_virt is not allowed to call this ctor due to the private access specifier and not being a friend.
If you leave out the explicit initialization of a base class (whether virtual or direct), it is default-initialized ([class.base.init]/8), that is, the default ctor is called implicitly (but you still must have access to the ctor, so it's the same as explicitly writting the call to the default ctor).
Some quotes:
[class.base.init]/1
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
[class.base.init]/7
A mem-initializer where the mem-initializer-id denotes a virtual base class is ignored during execution of a constructor of any class that is not the most derived class.
[class.base.init]/10
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.
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).
Emphasis mine.