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

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.