Why does virtual inheritance need to be specified in the middle of a diamond hierarchy?

前端 未结 5 2408
醉梦人生
醉梦人生 2021-02-20 06:24

I have diamond hierarchy of classes:

    A
  /   \\
 B     C
  \\   /
    D

To avoid two copies of A in D, we need to use virtual inheritance a

5条回答
  •  南方客
    南方客 (楼主)
    2021-02-20 06:45

    Why does virtual inheritance needs to be performed at B and C, even though the ambiguity is at D? It would have been more intuitive if it is at D.

    In your example, B and C are using virtual specifically to ask the compiler to ensure there's only one copy of A involved. If they didn't do this, they're effectively saying "I need my own A base class, I'm not expecting to share it with any other derived object". This could be crucial.

    Example of not wanting to share a virtual base class

    If A was some kind of container, B was derived from it and stored some particular type of object - say "Bat", while C stores "Cat". If D expects to have B and C independently providing information on a population of Bats and Cats they'd be very surprised if a C operation did something to/with the Bats, or a B operation did something to/with the Cats.

    Example of wanting to share a virtual base class

    Say D needs to provide access to some functions or data members that are in A, say "A::x"... if A is inherited independently (non-virtually) by B and C, then the compiler can't resolve D::x to B::x or C::x without the programmer having to explicitly disambiguate it. This means D can't be used as an A despite having not one but two "is-a" relationships implied by the derivation chain (i.e. if B "is a" A, and D "is a" B, then the user may expect/need to use D as if D "is a" A).

    Why is this feature designed like this by standards committee?

    virtual inheritance exists because it's sometimes useful. It's specified by B and C, rather than D, because it's an intrusive concept in terms of the design of B and C, and also has implications for the encapsulation, memory layout, construction and destruction and function dispatch of B and C.

    What can we do if B and C classes are coming from 3rd party library ?

    If D needs to inherit from both and provide access to an A, but B and C weren't designed to use virtual inheritance and can't be changed, then D must take responsibility for forwarding any requests matching the A API to either B and/or C and/or optionally another A it directly inherits from (if it needs a visible "is A" relationship). That might be practical if the calling code knows it's dealing with a D (even if via templating), but operations on the object via pointers to the base classes will not know about the management D is attempting to perform, and the whole thing may be very tricky to get right. But it's a bit like saying "what if I need a vector and I've only got a list", "a saw and not a screwdriver"... well, make the most of it or get what you really need.

    EDIT: My answer was to indicate B and C classes that they should not invoke A's constructor whenever its derived object gets created, as it will be invoked by D.

    That's an important aspect of this, yes.

提交回复
热议问题