Stroustrup discusses this case in section 4.5 of his 1989 multiple inheritance paper [PDF]:
The solution is to elaborate the conversion (casting) operation to
test for the pointer-value 0 [...]
The added complexity and run-time overhead are a test and an
increment.
The implementation checks explicitly for null-values and ensures that the result of the cast is still a null-value. This was true in C++98 and has not changed with C++11 and nullptr
.
This is especially important in the case of multiple base classes, where a cast from a derived class to one of the base classes might require changing the actual value of the pointer.
In your example, the layout of C
in memory will first contain the bytes for IA
, followed by the bytes for IB
. Casting to IA
is trival, as a pointer to the beginning of C
will also point to the beginning of the IA
part of C
. Casting to IB
on the other hand, requires shifting the C
pointer by the size of IA
. Performing this shifting in the nullptr case would lead to a non-null pointer after the cast, hence the special treatment for nulls.
As pointed out by aschepler, the relevant section in the standard is [conv.ptr] §4.10:
A prvalue of type “pointer to cv D
”, where D
is a class type, can be
converted to a prvalue of type “pointer to cv B
”, where B
is a base
class [...] of D
. [...] The result of the conversion is a pointer to
the base class subobject of the derived class object. The null pointer
value is converted to the null pointer value of the destination type.