Here is the rule from cppreference with my annotations:
5) If expression is a pointer or reference to a polymorphic type Base,
and new_type is a pointer or reference to the type Derived a run-time
check is performed:
This applies. B
is a base of C
.
a) The most derived object pointed/identified by
expression is examined. If, in that object, expression points/refers
to a public base of Derived, and if only one subobject of Derived type
is derived from the subobject pointed/identified by expression, then
the result of the cast points/refers to that Derived subobject. (This
is known as a "downcast".)
The most dervied object pointed by pa
is of type B
.
Although B
is a public base of C
, the particular instance which pa
points to, is not an instance of B
base subobject of a C
instance. The pointed B
instance is a "concrete" object. So, this case does not apply.
An example:
C c;
B* bp = &c; // bp points to base subobject of C
C* cp = dynamic_cast<C*>(bp);
assert(cp);
B b2;
B* bp2 = &b2; // bp does not point to a base subobject
C* cp2 = dynamic_cast<C*>(bp2);
assert(!cp2);
b) Otherwise, if expression points/refers
to a public base of the most derived object, and, simultaneously, the
most derived object has an unambiguous public base class of type
Derived, the result of the cast points/refers to that Derived (This is
known as a "sidecast".)
pa
does not point to a most derived object whose base class is C
, so this case does not apply.
An example of side cast:
struct base {
virtual ~base(){}; // for polymorphism
};
struct left : base {};
struct right : base {};
struct derived : left, right {};
derived d;
left* l = &d;
right* r = dynamic_cast<right*>(l);
c) Otherwise, the runtime check fails. If the
dynamic_cast is used on pointers, the null pointer value of type
new_type is returned. If it was used on references, the exception
std::bad_cast is thrown.
Neither 5a nor 5b cases apply, so this "otherwise" case 5c does.
- e is same as type. Sidecast?
Not a sidecast. A sidecast is explained in 5b. Casting to same type is just an identity cast (rarely useful, so not a commonly used terminology either).
It may be that the conditions of the book attempt describe whether the conversion is well-formed. Although, "then the cast will succeed" certainly seems to imply more. The quoted rules are not correct for describing whether the cast succeeds at runtime.
If the entire program is well-formed, then a compiler must compile the program. If an expression is ill-formed, then a compiler must give you a diagnostic message saying that you did wrong.
The example program that you've shown is well-formed and it must successfully compile. It does compile on my system.
dynamic_cast
can cast across class hierarchy; the source and target types may be unrelated to each other (there may be a third class derived from both of them). – Igor TandetnikB
is not aC
. – François AndrieuxB
. It is notC
. Basically, the object being dynamic casted has to have aC
"somewhere in it", in a manner of speaking. This is not true here. P.S. That quote is wrong also, true, what Igor said. – Sam Varshavchike
is a pointer to the same type astype
, the cast is simply a no-op. – Igor TandetnikC
object will appear out of thin air so that the result of the cast could point to it? – n. 1.8e9-where's-my-share m.