【发布时间】:2012-10-04 17:41:14
【问题描述】:
让我们从一个例子开始:
#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() 吗?
因此我正在寻找:
- 关于我自己的小程序的明确答案(我想不出一个)。
- 更改对象动态类型的合法方法的一个可能示例(一个就足够了)。
【问题讨论】:
-
您正在将
void*的地址传递给展示位置new,您确定这是您的本意吗? -
至于问题,我确实知道引用不能重新绑定到不同的对象,这就是这样做的。所以它似乎是未定义的?
-
@BЈовић 我假设
storage在static_cast<void*>(s)中被误写为s。 -
@SethCarnegie:感谢您的两个错别字。至于未定义……我也这么认为,但我想得到一个明确的答案。