Word description (code below): I have a library that provides a collection of classes. For each group of class we have two concrete types, (ClassA_Partial
, ClassA
), (ClassB_Partial
, ClassB
) etc. Each of these implements (Interface_Partial
, Interface
) respectively. Additionally, Interface
is a Interface_Partial
and each Class?
is a Class?_Partial
- creating a diamond inheritance pattern where the top is inherited virtually.
Why areInterface_Partial
functions ambiguous when inheriting both ClassA
and ClassB
?
struct Interface_Partial
{
virtual ~Interface_Partial();
virtual void f() = 0;
};
struct Interface
:
virtual Interface_Partial
{
virtual void g() = 0;
};
struct ClassA_Partial : public virtual Interface_Partial
{
void f() {};
};
struct ClassA : public Interface, public virtual ClassA_Partial
{
void g() {};
};
struct ClassB_Partial : public virtual Interface_Partial
{
void f() {};
};
struct ClassB : public Interface, public virtual ClassB_Partial
{
void g() {};
};
struct MyClass : public ClassA, public ClassB
{ }; // error C2250: MyClass : ambiguous inheritance of 'void Interface_Partial::f(void)'
Why can't we disambiguate the way we usually do when we inherit a common interface more than once? For example
struct ClassX : public Interface_Partial { void f() {} };
struct ClassY : public Interface_Partial { void f() {} };
class Another : public ClassX, public ClassY
{};
void func()
{
// This is ok
Another a;
a.ClassX::f();
// Why would this not work?
// unambiguously refers to the one and only f() function
// inherited via ClassA
MyClass b;
b.ClassA::f();
}
Because of the virtual inheritance, there is only one vtable for the base class Interface_Partial - once you use virtual inheritance, the "virtualness" infects all derived classes at all levels
The inheritance is ambigous because MyClass
has two different version of f() available - one from ClassA
and one from ClassB
. Because of the virtual inheritance of Interface_Partial
, you have two derived-class implementations that are at the same level and are trying to override the same virtual function. Declaring a virtual base class makes all derived classes share the virtual base class, including its vtable. The shared vtable gets updated to contain the pointer of the virtual function which should be called. But since there are two equally "good" ones to choose from, there is no way to pick one over the other.
In the other example you give, Interface_Partial
is a non-virtual base class for ClassX
and ClassY
, so each class is overriding a completely different virtual function. This is unambigous to the compiler, although when you call them, you have to specify which specific f()
you want to call.
You can resolve this by providing an implementation of f()
in MyClass
.