Diamond inheritance and pure virtual functions

2019-04-07 03:18发布

问题:

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------^

回答1:

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



回答2:

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.