Let us begin with an example:
#include <cstdio>
struct Base { virtual ~Base() {} virtual void foo() = 0; };
struct P: Base { virtual void foo() override { std::printf("Hello, World!"); } };
struct N: Base { virtual void foo() override {} };
void magic(Base& b);
// Example implementation that changes the dynamic type
// {
// void* s = dynamic_cast<void*>(&b);
// b.~B();
// new (s) N();
// }
int main() {
std::aligned_storage<sizeof(P), alignof(P)> storage;
void* s = static_cast<void*>(storage);
new (s) P();
Base& b = *static_cast<Base*>(s);
magic(b);
b.foo();
}
What, according to the Standard, should b.foo()
print ?
Personal opinion: it's undefined because b
got stale after we destroyed the instance in magic
. In this case, would replacing b.foo()
by static_cast<B*>(s)->foo()
make it legal ?
So now that we have an example that may (or not) be legal, the more general question at hand for all of us standardistas is whether changing the dynamic type of an object is ever allowed. We already know that the C++ compiler may reuse storage (fortunately), so it's a bit tricky.
The question might seem theoretical, however it has immediate application for compilers: may the compiler devirtualize b.foo()
to b.P::foo()
in the program above ?
And therefore I am looking for:
- a definite answer regarding my own little program (I could not come up with one).
- a possible example (a single would suffice) of a legal way of changing the dynamic type of an object.