Virtual base sub-objects are 'shared' between all base sub-objects in a complete object. Since A is is shared between D::C::B and D::B it can't tell which B object should have its f()
called as the override for A::f().
Consider:
#include <iostream>
struct A {
virtual void f() = 0;
virtual ~A() {}
};
struct B : virtual A
{
void f() { std::cout << "B\n"; }
};
struct C : virtual A
{
void f() { std::cout << "C\n"; }
};
struct D : C, B {};
int main() {
D d;
A *a = dynamic_cast<A*>(&d); // single shared A between B and C
a->f(); // Should B::f() be called, or C::f()?
}
The B and C base sub-objects in D both share the same A base sub-object. When we call A::f() a virtual look-up is done for the overriding function. But both B and C are trying to override it, so which one 'wins'? Does x->f()
print "B" or "C"? The answer is that a program that gets into the situation is ill-formed.
When we eliminate the sharing by making B and C inherit non-virtually, then the separate A base sub-objects each have their functions overridden by unique base classes:
#include <iostream>
struct A {
virtual void f() = 0;
virtual ~A() {}
};
struct B : A
{
void f() { std::cout << "B\n"; }
};
struct C : A
{
void f() { std::cout << "C\n"; }
};
struct D : C, B {};
int main() {
D d;
// two different A objects
A *a1 = static_cast<A*>(static_cast<B*>(&d));
A *a2 = static_cast<A*>(static_cast<C*>(&d));
a1->f();
a2->f();
}