让我们从一个例子开始:
#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();
}
根据标准,应该b.foo()
打印什么?
个人观点:它是未定义的,因为b
在我们销毁magic
. 在这种情况下,将替换b.foo()
为static_cast<B*>(s)->foo()
使其合法吗?
因此,现在我们有了一个可能(或不)合法的示例,对于我们所有的标准主义者来说,手头的更普遍的问题是是否允许更改对象的动态类型。我们已经知道 C++ 编译器可能会重用存储(幸运的是),所以这有点棘手。
这个问题似乎是理论上的,但它对编译器有直接的应用:编译器可以b.foo()
在b.P::foo()
上面的程序中去虚拟化吗?
因此,我正在寻找:
- 关于我自己的小程序的明确答案(我想不出一个)。
- 更改对象动态类型的合法方式的可能示例(单个就足够了)。