Consider the following code, where B
is a virtual base class inherited by D
through B1
and B2
:
#include <iostream>
class B
{
protected:
int x;
protected:
B(int x) : x{x}{std::cout << x << std::endl;}
};
class B1 : virtual public B
{
protected:
B1() : B(0){}
};
class B2 : virtual public B
{
protected:
B2() : B(10){}
};
class D : public B1, public B2
{
public:
D() : B(99), B1(), B2() {}
void print() {std::cout << "Final: " << x << std::endl;}
};
int main() {
D d;
d.print();
return 0;
}
See working example here. I use outputs in B
's constructor and after D
has been completely constructed to keep track of what's going on. Everything works fine, when I compile the above example with g++-4.8.1. It prints
99
Final: 99
because B
s constructor is called once from the most derived class (D
) and that also determines the final value of x
.
Now comes the strange part: If I change the line
D() : B(99), B1(), B2() {}
to the new uniform initialization syntax, i.e.
D() : B{99}, B1{}, B2{} {}
strange things happen. For one, it doesn't compile anymore, with the error
prog.cpp: In constructor ‘D::D()’:
prog.cpp:17:5: error: ‘B1::B1()’ is protected
B1() : B(0){}
^
prog.cpp:31:27: error: within this context
D() : B{99}, B1{}, B2{} {}
(and the same for B2
, see here) which doesn't make sense because I am using it in a derived class, so protected
should be fine. If I correct for that and make the constructors of B1
and B2
public instead of protected, everything gets totally messed up (see here), as the output becomes
99
0
10
Final: 10
So, in fact, the parts of B1
s and B2
s constructors that initialize B
are still executed and even change the value of x
. This should not be the case for virtual inheritance. And remember, the only things I have changed are
- public instead of protected constructors in
B1
andB2
- use
classname{}
syntax in member initialization list ofD
instead ofclassname()
.
I cannot believe such a basic thing goes wrong in gcc. But I tested it with clang on my local machine and there, all three cases compile and run as intended (i.e. like the first example above). If it's not a bug, can someone please point me to what I am missing?
EDIT: My first search somehow didn't bring it up, but now I found this other question, showing at least the protected/public error. However, this was gcc-4.7, so I would have expected it to be dealt with in gcc-4.8. So, should I conclude initializer lists are just fundamentally messed up in gcc!?
See Question&Answers more detail:os