22.2.2 Multiple Inheritance1

When only single inheritance is used, a class and its base classes constitute a tree rooted in a single
base class. This is simple but often constraining. When multiple inheritance is used, there is no
single root. In itself, this doesn’t complicate matters much. However, if a class appears more than
once in a hierarchy, we must be a bit careful when we refer to the object or objects that represent
that class.
Naturally, we try to keep hierarchies as simple as our application allows (and no simpler).
However, once a nontrivial hierarchy has been constructed, we sometimes need to navigate it to
find a specific class to use. This need occurs in two variants:

  • Sometimes, we want to explicitly name a base class for use as an interface, for example, to resolve an ambiguity or to call a specific function without relying on the virtual function mechanism (an explicitly qualified call; §21.3.3).
  • Sometimes, we want to obtain a pointer to a subobject of a hierarchy giv en a pointer to
    another, for example, to get a pointer to the complete derived class object from a pointer to a
    base (a downcast; §22.2.1) or to get a pointer to a base class object from a pointer to another
    base (a crosscast; §22.2.4).
    Here, we consider how to navigate a class hierarchy using type conversions (casts) to gain a pointer
    of the desired type. To illustrate the mechanisms available and the rules that guide them, consider a
    lattice containing both a replicated base and a virtual base:
class Component
: public virtual Storable { /* ... */ };
class Receiver
: public Component { /* ... */ };
class Transmitter
: public Component { /* ... */ };
class Radio
: public Receiver, public Transmitter { /* ... */ };

or graphically:
graph

Here, a Radio object has two subobjects of class Component . Consequently, a dynamic_cast from
Storable to Component within a Radio will be ambiguous and return a 0 . There is simply no way of
knowing which Component the programmer wanted:

void h1(Radio& r)
{
Storable∗ ps = &r; // a Radio has a unique Storable
// ...
Component∗ pc = dynamic_cast<Component∗>(ps);  // pc = 0; a Radio has two Components
// ...
}

In general – and typically – a programmer (and a compiler looking at a single translation unit) does
not know the complete class lattice. Instead, code is written with the knowledge of some sublattice.
For example, a programmer might know only about the Transmitter part of a Radio and write:

void h2(Storable∗ ps)  // ps might or might not point to a Component
{
if (Component∗ pc = dynamic_cast<Component∗>(ps)) {
// we have a component!
}
else {
// it wasn’t a Component
}
}

The ambiguity for a pointer to a Radio object is not in general detectable at compile time.
This kind of run-time ambiguity detection is needed only for virtual bases. For ordinary bases,
there is always a unique subobject of a given cast (or none) when downcasting (that is, toward a derived class; §22.2). The equivalent ambiguity for virtual bases occurs when upcasting (that is,
toward a base), but such ambiguities are caught at compile time.
c++多态,类型转换背后实际上是一个大对象与内部父类子对象之间的转换,如上面的图,只要是同一个类型出现多个子对象,不管是像下还是向上造型,都是含糊的


  1. 摘自 intermediete 第647页
最后修改:2019 年 03 月 01 日
如果觉得我的文章对你有用,请随意赞赏