An ambiguous base class is a base class that is included in a derived class twice. Because you can't just derive from a class twice, this usually happens by having parent classes who both derive from the same class without virtualizing that common base.
The storage implications of ambiguous base classes are relatively simple. Because each parent class's memory layout contains the base, we know where the two bases will be in memory - we simply apply our pattern for inheritance via containment recursively.
class R { };
class B1 : public R { };
class B2 : public R { };
class D : public B1, public B2 { };
gives us
struct R {
vtable * vt;
};
struct B1 {
R base;
};
struct B2 {
R base;
};
struct D {
B1 base;
B2 base;
};
Thus we have two instance of R: obj.base1.base and obj.base2.base reference each copy of R.
Static casts are casts that can be computed knowing only compile-time information - that is, casts that don't require knowing the full class of the casted object.
A static cast from D to R is illegal because it is ambiguous. Do we want R via B1 or B2? We don't know, and because the cast is static the compiler knows we don't know at compile time and generates an error.
If you cast to B1 first and then R it is legal - you have disambiguated. (This should not be surprising - if we simply had an object of type B1, casting to R would work! Remember, memory layout doesn't change with type!)
Static casts give us compile-time checking of all casts for ambiguity - we always know what we are getting. Next I'll cover dynamic casts and ambiguous base classes, which are more complex.