As long as the pointer to a base type actually points to an instance of a derived type, then such usage is not undefined according to the C++ standard. However, in your code sample, the pointer b
does not point to an instance of B
or any of its derived types (which there are none), it points to an instance of A
. So your code does in fact invoke undefined behavior.
I've found an answer on S.O that says it can lead to UB, testing it,
it both compiled and worked correctly.
The fact that some code compiles and works correctly does not rule out the possibility of code invoking undefined behavior, because undefined behavior includes "appears to work". The reason why you should avoid undefined behavior is because there's no guarantee that it will work the same way the next time you invoke UB.
Is it undefined behavior? If it is what would be a correct approach to
this problem?
In your sample, yes, it is undefined behavior. The correct approach would depend on what your code is actually supposed to do, as the example you provide is an academic example at best.
To make it clear, the following modification to your main()
function has well-defined behavior and is explictly allowed by the C++ standard:
B objectB;
A* ptrA = &objectB;
B* b = static_cast<B*>(ptrA);
b->Show();
Here, it's well defined because the pointer ptrA
actually points to an instance of B
, even though the pointer itself has type A*
. In the above example, casting from A*
to B*
then invoking one of B
's functions on the casted pointer will work. The difference is that in the example in your question, b
does not actually point to an instance of B
.
The relevant clause (emphasis mine):
C++ standard 5.2.9/8 Static cast [expr.static.cast]
An rvalue of type “pointer to cv1 B
”, where B
is a class type, can be
converted to an rvalue of type “pointer to cv2 D
”, where D
is a class
derived (clause 10) from B
, if a valid standard conversion from
“pointer to D
” to “pointer to B
” exists (4.10), cv2 is the same
cv-qualification as, or greater cv-qualification than, cv1, and B
is
not a virtual base class of D
. The null pointer value (4.10) is
converted to the null pointer value of the destination type. If the
rvalue of type “pointer to cv1 B
” points to a B
that is actually a
sub-object of an object of type D
, the resulting pointer points to the
enclosing object of type D
. Otherwise, the result of the cast is
undefined.