static_cast
for performing downcast does not perform any safety checks. Since it's possible for a Base&
to be referencing an instance of A
, the cast proceeds and since it's NOT actually referencing an A
, we enter undefined behavior territory*.
A dynamic_cast
on the other hand is safer. It will perform a check and throw an exception in the case of reference casting, or return nullptr
in the case of pointer casting†.
However, since your base class lacks any virtual functions, dynamic_cast
is impossible, so you'd need to modify it with at least a virtual destructor:
class Base{
public:
int m_object;
virtual ~Base()=default;
};
Now if we tried to cast:
A* a = dynamic_cast<A*>(&base);
if (a)
a->arggh();
else
std::cout << "null\n";
Our output would be
null
*Relevant standardese can be found in [expr.static.cast]:
[for a cast like static_cast<D&>(b)
where b
is an instance of a base class for D
], If the object of type “cv1 B
” is actually a base class subobject of an object of type D
, the result refers to the enclosing object of type D
. Otherwise, the behavior is undefined.
†Relevant standardese at [expr.dynamic.cast]
The value of a failed cast to pointer type is the null pointer value of the required result type. A failed cast to reference type throws an exception of a type that would match a handler of type
std::bad_cast