Suppose I have something along these lines:
class Base {
public:
Base(int value) : value_(value) {}
int getValue() const { return value_; }
private:
int value_;
};
class Derived : public Base {
public:
// Derived only has non-virtual functions. No added data members.
int getValueSquared() const { return value_ * value_; }
}
And I do the following:
Base* base = new Base(42);
Derived* derived = static_cast<Derived*>(base);
std::cout << derived->getValueSquared() << std::endl;
Strictly speaking, this is UB. Practically speaking, it works just fine.
Actual data members from Base (e.g., int value_
) have to be located at the same offsets whether the object is an actual Base
or an actual Derived
(otherwise, good luck upcasting). And getValueSquared()
isn't part of the actual memory footprint of a Derived
instance so it's not like it will be "missing" or unconstructed from the in-memory Base object.
I know that UB is all the reason I need not to do this but, logically, it seems it would always work. So, why not?
I am asking because it seems like an interesting quirk to discuss...not because I plan on using it in production.