Imagine a standard diamond inheritance. Class A defines pure virtual function fx, class B defines implementation for fx, classes C and D do nothing with fx. When trying to call fx on instance of class D you'll get 'ambiguous function call' error although there is only one implementation of fx. This can be solved by B and C inheriting from A in virtual manner. Is it a correct solution for the problem? How exactly does virtual inheritance handle merging of virtual function tables?
A--->B--->D
\--->C------^
... Note, Herb Sutter wrote 3 excellent articles about multiple inheritance (1) here, (2) here and (3) here . He wrote a whole other bunch of useful articles in guru-of-the-week here. Highly recommended ...
First, i'm not sure that i get your hierarchy right. I take it it is like this:
struct A {
virtual void F() = 0;
};
struct B : A { void F() { } };
struct C : A { };
struct D : B, C { };
Well, D is abstract, because there are two A
subobjects in an object of type D: One that is made concrete by B
through the lattice of B, and one that is still abstract in the lattice going through C
. I take it you have a pointer to D
and try to call F
. Yes, an ambiguity arises, because the compiler finds two functions F
in two separate lattices:
D -> B::F
D -> C -> A::F
Looking like this:
F() F()
A A
| |
F() B C
\ /
D
You can fix that situation formally by deriving from A virtually:
struct B : virtual A { void F() { } };
struct C : virtual A { };
struct D : B, C { };
You then have this situation, called diamond inheritance:
F()
A
/ \
F() B C
\ /
D
And doing the lookup, it finds that there is B::F
overriding A::F
. Although A::F
can still be reached through D::C::A
, that is not an ambiguity anymore, because A
was inherited virtual.
Whether this is the correct solution in your particular problem - that's of course not certain. There are most often better ways than deriving virtual from a class. To your question about merging of virtual function tables - that's completely depending on the implementation. GCC
, as far as i know, will keep a pointer to the one A instance in the virtual table of D
, if we derive virtual.
Is it a correct solution for the problem?
"Diamond" inheritance is problematic, and the correct explanation of the solution takes a bit of explaining. I recommend you read the following chapters of Meyers' Effective C++:
- Item 26, Guard against potential ambiguity
- Item 43, Use multiple inheritance judiciously.