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
).