Is casting from a pointer polymorphic base object to pointer to a derived object via explicit cast and accessing only functions ill-formed?

Is casting from a pointer polymorphic base object to pointer to a derived object via explicit cast and accessing only functions ill-formed?
typescript
Ethan Jackson

Given a base/derived class polymorphic relationship (established below via the virtual destructor), if I explicitly (C-style) cast a pointer-to-a-base object to a pointer-to-a-derived object, is this ill-formed/undefined? I know this is not good practice.

In this specific example (the one I am primarily concerned about), the pointed-to object is actually a Base, and the Derived class has no data, only newly defined functions. Does this make a difference?

class Base { public: Base() : data(1) {}; virtual ~Base(){}; protected: int data; }; class Derived : public Base { public: Derived(){}; virtual ~Derived(){}; int new_function(){return data;}; }; int main() { Base b; return ((Derived *)&b)->new_function(); //undefined? }

From my understanding of explicit casting, this would result in an static_cast. The static_cast explanation states:

if expression is actually not a base class subobject of an object of type Derived, the behavior is undefined.

My guess here is that the Base class is not a subobject of the Derived in my example, and so the result is undefined, but I'm not sure. I know a dynamic_cast will fail (nullptr/exception), which makes sense because the dynamic type here is a Base.

If there is specific information on the VS2010 VC++ compiler-specific behavior, that's a bonus.

I tried running this on https://www.onlinegdb.com/online_c++_compiler and it functions, but I know this doesn't mean it's ill-formed and could be compiler-specific.

Answer

Yes, this is bad. You do not have a Derived object, only a Base object, so calling Derived::new_function() on that object is undefined behavior.

Derived::new_function() is accessing the Base::data member via its own this pointer of type Derived*. Depending on how the compiler lays out the object in memory, adjusting a Derived* pointer to a Base* pointer may require adjustments that would be illegal when this is not pointing at a valid Derived object, thus new_function() would access incorrect/invalid memory.

Related Articles