C++ Undefined Behavior – Incorrect Cast or Usage?

c++castinglanguage-lawyerundefined-behavior

If I do a cast from a Base to a Derived type, but the Base type isn't an instance of derived type, but only use the result if it is, do I get undefined behaviour?

Hard to understand what I'm asking? take a look at this example:

struct Animal { int GetType(){...} };
struct Dog : Animal { bool HasLoudBark(){...}};
struct Cat : Animal { bool HasEvilStare(){...} };

Animal * a = ...;
Dog* d = static_cast<Dog*>(a);

if(a->GetType() == DogType && d->HasLoudBark())
    ....

In this case a may or not be a Dog. We always do the static_cast of a to Dog * d but we never use d unless we're sure its a Dog.

Assuming that a is not a Dog, is this undefined behaviour at the point of the cast? Or is it defined as we don't actually use d unless it is really is a Dog?

References to the relevant parts of the standard are appreciated.

(Yes I know I can use dynamic_cast, and RTTI, and probably this isn't great code, but I'm more interested in whether this is valid)

Best Answer

The cast itself has undefined behaviour. Quoting C++17 (n4659) [expr.static.cast] 8.2.10/11:

A prvalue of type “pointer to cv1 B”, where B is a class type, can be converted to a prvalue of type “pointer to cv2 D”, where D is a class derived (Clause 13) from B, if cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. ... If the prvalue of type “pointer to cv1 B” points to a B that is actually a subobject of an object of type D, the resulting pointer points to the enclosing object of type D. Otherwise, the behavior is undefined.

Related Question