I am trying to understand better the concept of virtual inheritance, and what are its perils.
I read in another post (Why is Default constructor called in virtual inheritance?) that it (= virtual inheritance) changes the order of constructor call (the "grandmother" is called first, while without virtual inheritance it doesn't).
So I tried the following to see that I got the idea (VS2013):
#define tracefunc printf(__FUNCTION__); printf("\r\n")
struct A
{
A(){ tracefunc; }
};
struct B1 : public A
{
B1(){ tracefunc; };
};
struct B2 : virtual public A
{
B2() { tracefunc; };
};
struct C1 : public B1
{
C1() { tracefunc; };
};
struct C2 : virtual public B2
{
C2() { tracefunc; };
};
int _tmain(int argc, _TCHAR* argv[])
{
A* pa1 = new C1();
A* pa2 = new C2();
}
The output is:
A::A
B1::B1
C1::C1
A::A
B2::B2
C2::C2
Which is not what I expected (I expected the order of the 2 classes will be different).
What am I missing? Can someone explain or direct me to a source that explains it better?
Thanks!
In your example, your output is to be expected. Virtual inheritance comes into play in the instance when you have a class with multiple inheritance who's parent classes also inherit from the same class/type (i.e. the "diamond problem"). In your example, your classes might be set up to virtually inherit (if needed elsewhere in the code), but they don't necessarily 'virtually inherit' based on your example since none of the derived classes (B1/B2/C1/C2) do more than inherit directly from A.
To expand, I've tweaked your example to explain a little more:
#include <cstdio>
#define tracefunc printf(__FUNCTION__); printf("\r\n")
struct A
{
A() { tracefunc; }
virtual void write() { tracefunc; }
virtual void read() { tracefunc; }
};
struct B1 : public A
{
B1() { tracefunc; };
void read(){ tracefunc; }
};
struct C1 : public A
{
C1() { tracefunc; };
void write(){ tracefunc; }
};
struct B2 : virtual public A
{
B2() { tracefunc; };
void read(){ tracefunc; }
};
struct C2 : virtual public A
{
C2() { tracefunc; };
void write(){ tracefunc; }
};
// Z1 inherits from B1 and C1, both of which inherit from A; when a call is made to any
// of the base function (i.e. A::read or A::write) from the derived class, the call is
// ambiguous since B1 and C1 both have a 'copy' (i.e. vtable) for the A parent class.
struct Z1 : public B1, public C1
{
Z1() { tracefunc; }
};
// Z2 inherits from B2 and C2, both of which inherit from A virtually; note that Z2 doesn't
// need to inherit virtually from B2 or C2. Since B2 and C2 both virtual inherit from A, when
// they are constructed, only 1 copy of the base A class is made and the vtable pointer info
// is "shared" between the 2 base objects (B2 and C2), and the calls are no longer ambiguous
struct Z2 : public B2, public C2
{
Z2() { tracefunc; }
};
int _tmain(int argc, _TCHAR* argv[])
{
// gets 2 "copies" of the 'A' base since 'B1' and 'C1' don't virtually inherit from 'A'
Z1 z1;
// gets only 1 "copy" of 'A' base since 'B2' and 'C2' virtualy inherit from 'A' and thus "share" the vtable pointer to the 'A' base
Z2 z2;
z1.write(); // ambiguous call to write (which one is it .. B1::write() (since B1 inherits from A) or A::write() ?)
z1.read(); // ambiguous call to read (which one is it .. C1::read() (since C1 inherits from A) or A::read() ?)
z2.write(); // not ambiguous: z2.write() calls C2::write() since it's "virtually mapped" to/from A::write()
z2.read(); // not ambiguous: z2.read() calls B2::read() since it's "virtually mapped" to/from A::read()
return 0;
}
While it might be "obvious" to us humans which call we intend to make in the case of the z1 variable, since B1 doesn't have a write method, I would "expect" the compiler to choose the C1::write method, but due to how the memory mapping of objects work, it presents a problem since the base copy of A in the C1 object might have different information (pointers/references/handles) than the copy of the A base in the B1 object (since there's technically 2 copies of the A base); thus a call to B1::read() { this->write(); } could give unexpected behaviour (though not undefined).
The virtual keyword on a base class specifier makes it explicit that other classes that virtually inherit from the same base type, shall only get 1 copy of the base type.
Note that the above code should fail to compile with compiler errors explaining the ambiguous calls for the z1 object. If you comment out the z1.write(); and z1.read(); lines the output (for me at least) is the following:
A::A
B1::B1
A::A
C1::C1
Z1::Z1
A::A
B2::B2
C2::C2
Z2::Z2
C2::write
B2::read
Note the 2 calls to the A ctor (A::A) before Z1 is constructed, while Z2 only has 1 call to the A constructor.
I recommend reading the following on virtual inheritance as it goes more in depth on some of the other pitfalls to take note of (like the fact that virtually inherited classes need to use the initialization list to make base class ctor calls, or that you should avoid using C-style casts when doing such a type of inheritance).
It also explains a little more to what you were initially alluding to with the constructor/destructor ordering, and more specifically how the ordering is done when using multiple virtual inheritance.
Hope that can help clear things up a bit.
The output of compiler is right. In fact, this is about the goal of virtual inheritance. Virtual inheritance is aimed to solve the 'Diamond problem' in the multiple inheritance. For example, B inherits from A, C inherits from A and D inherits from B, C. The diagram is like this:
A
| |
B C
| |
D
So, D has two instances A from B and C. If A has virtual functions, there is a problem.
For example:
struct A
{
virtual void foo(){__builtin_printf("A");}
virtual void bar(){}
};
struct B : A
{
virtual void foo(){__builtin_printf("B");}
};
struct C : A
{
virtual void bar(){}
};
struct D : B, C
{
};
int main()
{
D d;
d.foo(); // Error
}
If I use my xlC compiler to compile and run:
xlC -+ a.C
The error message is like that:
a.C:25:7: error: member 'foo' found in multiple base classes of different types
d.foo(); // Error
^
a.C:9:18: note: member found by ambiguous name lookup
virtual void foo(){__builtin_printf("B");}
^
a.C:3:18: note: member found by ambiguous name lookup
virtual void foo(){__builtin_printf("A");}
^
1 error generated.
Error while processing a.C.
The error message is very clear, member 'foo' found in multiple base classes of different types. If we add virtual inheritance, the problem is solved. Because the construction rights of A is handled by D, there is one instance of A.
Back to your code, the inheritance diagram is like this:
A A
| |
B1 B2
| |
C1 C2
There is no 'diamond problem', this is only single inheritance. So, the construction order is also A->B2->C2, there is no difference of output.
You won't be able to see any difference in the output because the output will be same in any of the following class hiearchies:
Hiearchy 1
class A {};
class B2 : virtual public A {};
class C2 : virtual public B2 {};
Hiearchy 2
class A {};
class B2 : public A {};
class C2 : virtual public B2 {};
Hiearchy 3
class A {};
class B2 : virtual public A {};
class C2 : public B2 {};
Hiearchy 3
class A {};
class B2 : public A {};
class C2 : public B2 {};
In all these case, A::A() will be executed first, followed by B2::B2(), and then C2::C2().
The difference between them is when does A::A() get called. Does it get called from B2::B2(), or C2::C2()?
I am not 100% clear on the answer for Hiearchy 1. I think B2::B2() should get called from C2::C2 since B2 is a virtual base class of C. A::A() should get called from B2:B2() since A is a virtual base class of B2. But I could be wrong on the exact order.
In Hierarchy 2, A::A() will be called from B2::B2(). Since B2 is the virtual base class of C2, B2::B2() gets called from C2::C2(). Since A is a normal base class of B2, A::A() gets called from B2::B2().
In Hierarchy 2, A::A() will be called from C2::C2(). Since A is a virtual base class, A::A() gets called from C2::C2(). B2::B2() gets called after the call to A::A() is completed.
In Hierarchy 4, A::A() will be called from B2::B2(). I think this case needs no explanation.
To clarify my doubt regarding Hiearchy 1, I used the following program:
#include <iostream>
class A
{
public:
A(char const *from) { std::cout << "Called from : " << from << std::endl; }
};
class B2 : virtual public A
{
public:
B2() : A("B2::B2()") {}
};
class C2 : virtual public B2
{
public:
C2() : A("C2::C2()") {}
};
int main()
{
C2 c;
}
I got the following output:
Called from : C2::C2()
This confirms what #T.C indicated in his comment, which is different from what I had expected. A::A() gets called from C2::C2, not from B2::B2.
Related
class A
/ \
class B1 class B2
All classes have only public members.
Class A is publicly inherited and contains virtual member functions and non-virtual member functions with default print(cout) statements, class B1 and class B2 has only non-virtual functions, with definition of the virtual functions from class A.
I want to know how to access all members of B2 using pointer of B1, which casting could be used.
For example:
B2 obj_b2;
B1* b1_ptr=&obj_b2;
// Using b1_ptr, access all members of obj_b2
If yes, then whether this can be extended further into more deep branches like:
class A
/ \
class B1 class B2
/ \ / \
class C1 ... ... ...
(Accessing members of class C1, etc. from second branch)
EDIT 1:
Maybe this will help; this is the example that I have written:
#include<iostream>
using namespace std;
class A{
public:
virtual void v_f1(){
cout<<"virtual A::v_f1()\n";
}
void f1(){
cout<<"A::f1()\n";
}
};
class B1 : public A{
public:
virtual void v_f2(){
cout<<"virtual B1::v_f2()\n";
}
void v_f1(){
cout<<"A<-B1::v_f1()\n";
}
void f2(){
cout<<"B1::f2()\n";
}
};
class C1 : public B1{
public:
void v_f2(){
cout<<"B1<-C1::v_f2()\n";
}
void f3(){
cout<<"C1::f3()\n";
}
};
class D : public C1{
public:
void f4(){
cout<<"D::f4()\n";
}
};
class B2 : public A{
public:
void v_f(){
cout<<"A<-B2::v_f()\n";
}
void f5(){
cout<<"B2::f5()\n";
}
};
class C2 : public B2{
public:
void f6(){
cout<<"C2::f6()\n";
}
};
int main(){
C2 c2_obj;
C2* c2_obj_ref=&c2_obj;
D* d_ptr = dynamic_cast<D*>(c2_obj_ref);
// This statement gives segmentation fault,
// if commented out, the code works fine.
d_ptr->v_f();
// These work fine
d_ptr->f();
dynamic_cast<C2*>(d_ptr)->f5();
dynamic_cast<C2*>(d_ptr)->f6();
return 0;
}
An object of type B1 does not have the members that B2 declares.
If you try to treat an object as a type that it is not, your program is ill-formed.
You basically can't.
B1 inherits from A, but know nothing from any other class the inherits from A.
You can upcast a B1 object to A or down cast A to a B1 objet. If you do both you'll eitehr have a bad cast exception or a null ptr (see comments)
What you are doing here is upcasting a B2 to A then downcasting an A to a B1 (if it compiles what I'm not sure of) so you may loose some B2 informations from the upcast that you can recollect in you downcast.
If you want to do this, you should rather wonder if B1 and B2 are basically the same class and should differ in a different way. For instance is say A is Character, B1 is Soldier and B2 is Creature, you could just have class A and inherited class AInstance with a private parameter bool soldier and bool creature that you can then use for printing or algorithm purposes.
Hope that helps !
The following code won't compile:
class A {
public:
A(int) {}
};
class B: virtual public A {
public:
B(): A(0) {}
};
// most derived class
class C: public B {
public:
C() {} // wrong!!!
};
If I call A's constructor in C's constructor initialization list, that is:
// most derived class
class C: public B {
public:
C(): A(0) {} // OK!!!
};
it does work.
Apparently, the reason is because virtual base classes must always be constructed by the most derived classes.
I don't understand the reason behind this limitation.
Because it avoids this:
class A {
public:
A(int) {}
};
class B0: virtual public A {
public:
B0(): A(0) {}
};
class B1: virtual public A {
public:
B1(): A(1) {}
};
class C: public B0, public B1 {
public:
C() {} // How is A constructed? A(0) from B0 or A(1) from B1?
};
Because in the class hierarchy having a virtually inherited base class, the base class would/may be shared by multiple classes (in diamond inheritance for example, where the same base class is inherited by multiple classes). It means, there would be only one copy of the virtually-inherited base class. It essentially means, the base class must be constructed first. It eventually means the derived class must instantiate the given base class.
For example:
class A;
class B1 : virtual A;
class B2 : virtual A;
class C: B1,B2 // A is shared, and would have one copy only.
I find this rule error-prone and cumbersome (but then, what part of multiple inheritance isn't?).
But the logically imposed order of construction must differ from the case of normal (non-virtual) inheritance. Consider Ajay's example, minus virtual:
class A;
class B1 : A;
class B2 : A;
class C: B1,B2
In this case for each C two As are constructed, one as part of B1, the other one as part of B2. The code of the B classes is responsible for that, and can do it. The order of events is:
Start C ctor
Start B1 ctor
A ctor (in B's ctor code)
End B1 ctor
Start B2 ctor
A ctor (in B's ctor code)
End B2 ctor
End C ctor
Now consider virtual inheritance in
class A;
class B1 : virtual A;
class B2 : virtual A;
class C: B1,B2
One order of event is
Start C ctor
A ctor // not B's code!
Start B1 ctor
// NO A ctor
End B1 ctor
Start B2 ctor
// NO A ctor
End B2 ctor
End C ctor
The important logical distinction is that the virtually inherited base class sub-object of type A is part of the most derived class and under the control of it (here C).
B's constructors know nothing about and cannot access A. Consequently they cannot construct sub-objects of A, including base classes.
The following code won't compile:
class A {
public:
A(int) {}
};
class B: virtual public A {
public:
B(): A(0) {}
};
// most derived class
class C: public B {
public:
C() {} // wrong!!!
};
If I call A's constructor in C's constructor initialization list, that is:
// most derived class
class C: public B {
public:
C(): A(0) {} // OK!!!
};
it does work.
Apparently, the reason is because virtual base classes must always be constructed by the most derived classes.
I don't understand the reason behind this limitation.
Because it avoids this:
class A {
public:
A(int) {}
};
class B0: virtual public A {
public:
B0(): A(0) {}
};
class B1: virtual public A {
public:
B1(): A(1) {}
};
class C: public B0, public B1 {
public:
C() {} // How is A constructed? A(0) from B0 or A(1) from B1?
};
Because in the class hierarchy having a virtually inherited base class, the base class would/may be shared by multiple classes (in diamond inheritance for example, where the same base class is inherited by multiple classes). It means, there would be only one copy of the virtually-inherited base class. It essentially means, the base class must be constructed first. It eventually means the derived class must instantiate the given base class.
For example:
class A;
class B1 : virtual A;
class B2 : virtual A;
class C: B1,B2 // A is shared, and would have one copy only.
I find this rule error-prone and cumbersome (but then, what part of multiple inheritance isn't?).
But the logically imposed order of construction must differ from the case of normal (non-virtual) inheritance. Consider Ajay's example, minus virtual:
class A;
class B1 : A;
class B2 : A;
class C: B1,B2
In this case for each C two As are constructed, one as part of B1, the other one as part of B2. The code of the B classes is responsible for that, and can do it. The order of events is:
Start C ctor
Start B1 ctor
A ctor (in B's ctor code)
End B1 ctor
Start B2 ctor
A ctor (in B's ctor code)
End B2 ctor
End C ctor
Now consider virtual inheritance in
class A;
class B1 : virtual A;
class B2 : virtual A;
class C: B1,B2
One order of event is
Start C ctor
A ctor // not B's code!
Start B1 ctor
// NO A ctor
End B1 ctor
Start B2 ctor
// NO A ctor
End B2 ctor
End C ctor
The important logical distinction is that the virtually inherited base class sub-object of type A is part of the most derived class and under the control of it (here C).
B's constructors know nothing about and cannot access A. Consequently they cannot construct sub-objects of A, including base classes.
I have a diamond problem which look like this:
__ A
/ |\
| B | \
v|/v v\|v \v
B2 B3 C
\v /v /
B4 /
\ /
D
I tried many way to make the best virtual inheritance to get no duplicates but I couldn't find a solution. The class A contains a position. Here's a sample output:
Call: A() position pointer is: 0x2203be8
Call: B()
Call: B2() position pointer is: 0x2203be8
Call: B3() position pointer is: 0x2203be8
Call: C() position pointer is: 0x2203a28
Call: B4() position pointer is: 0x2203be8
Call: D() position pointer is: 0x2203a28
Why does D and C don't have the same pointer for position? Why there's no constructor for this A::position? What virtual inheritance should I make to solve this? Thanks.
EDIT:
Here's a code sample:
class A;
class B;
class B2 : public virtual B, public virtual A;
class B3 : public virtual B, public virtual A;
class C : public virtual A;
class B4 : public virtual B2, public virtual B3;
class D : public B4, public C;
EDIT 2:
To make the output, I put this code inside each constructors:
A::A()
{
std::cerr << "Call: A() position pointer is: " << &_position << std::endl;
}
Since you say the below code, which works on the implementations I have, is broken for you then obviously the code isn't the problem. The problem is with something else in your set up; perhaps a compiler bug. You should narrow down what else could be the cause of the problem; since the code itself is ruled out as a problem perhaps the best next step is to update your compiler.
In any case that makes this question rather specific to your set up. If you do find a solution that might apply to other people then you should come back and post it. Until then I'm voting to close this question.
I'm trying to reproduce your issue. Here's the code I'm using:
#include <iostream>
struct A { int a; };
struct B { int b; };
struct B2 : virtual B, virtual A {};
struct B3 : virtual B, virtual A {};
struct B4 : virtual B2, virtual B3 {}; // these virtuals are unnecessary in this case...
struct C : virtual A {};
struct D : B4, C {};
int main() {
D d;
std::cout << &((B4*)&d)->a << '\n';
std::cout << &((B3*)(B4*)&d)->a << '\n';
std::cout << &((B2*)(B4*)&d)->a << '\n';
std::cout << &((A*)(B2*)(B4*)&d)->a << '\n';
std::cout << &((A*)(B3*)(B4*)&d)->a << '\n';
std::cout << &((C*)&d)->a << '\n';
std::cout << &((A*)(C*)&d)->a << '\n';
}
But the results I get are as expected, where the a member is the same for every object. I get the same results if I use print the addresses out in the constructors as well: http://ideone.com/8FdQ1O
If I make a slight change and remove the virtual keyword from C's definition:
...
struct C : A {};
...
(version using constructors)
then I do see the problem you describe where C has it's own A sub-object different from the virtual one used by B2, B3, and B4.
Are you sure you're using the virtual keyword in all the places you need it? The results you show seem to indicate you're missing it somewhere. Also I note that the output you show does not reflect the same order of constructors as the code fragments you show; the output shows A() first, but the code indicates that B() should be executed first.
The way virtual inheritance works is that a most derived type will contain a single virtual sub-object for each type that is virtually inherited anywhere in the inheritance tree. Additionally the most derived type will contain a sub-object for each instance of non-virtual inheritance:
struct A {};
struct B : virtual A {};
struct C : A, B {};
struct D : virtual A, C {};
struct E : A, D {};
struct F : virtual A, E {};
struct G : A, F {};
G g;
g contains a total of four A sub objects; one for each time A is non-virtually inherited (in C, E, and G), and once for all of the times A is virtually inherited (in B, D, and F).
What code do you currently have? It looks like the solution is going to be:
class D;
class C : public virtual D;
class B4 : public virtual D;
class B2 : public virtual B4;
class B3 : public virtual B4;
class B : public B2, public B3;
class A : public B2, public B3, public C;
based on your diagram. If I'm reading it wrong and A is the base, not D. Then it would need to look like this:
class A;
class B;
class B2 : public virtual B, public virtual A;
class B3 : public virtual B, public virtual A;
class C : public virtual A;
class B4 : public virtual B2, public virtual B3;
class D : public B4, public C;
Why does D and C don't have the same pointer for position?
Because you are non-virtually inheriting D from B4 and C. That means you have two copies of A (and two pointers).
In D constructor &B4::position is different from &C::position
Why there's no constructor for this A::position?
No idea, any chances that your A class has more than one constructor, and that a default-silent constructor is called by C::C()?
What virtual inheritance should I make to solve this?
Make all virtual. That means that you need to explicitly call every constructor from D::D() (i.e. A::A(),B::B(),B2::B2(),B3::B3(),C::C() ).
Tbh I believe you should reconsider your hierarchy. I don't know the details, but it seems that your problem has a cleaner solution via component-design.
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