有人会解释为什么下面的代码有效,我在Visual Studio .NET 2008上测试过它,在Cygwin和ideone.com上测试g ++。更重要的是我想知道它是否有效。请注意,A
和B
是不相关的类型。
编辑:关注@ leftaroundabout的评论我对我的代码进行了以下更改
#include <iostream>
#include <cstdlib>
class A
{
public:
virtual void Bar()
{
std::cout << "A::Bar() -> " << this << std::endl;
}
virtual void Foo()
{
std::cout << "A::Foo() -> " << this << std::endl;
}
};
class B
{
public:
virtual void Foo()
{
std::cout << "B::Foo() -> " << this << std::endl;
}
};
int main()
{
B* b = reinterpret_cast<B*>( new A );
b->Foo();
return EXIT_SUCCESS;
}
程序输出消息:
A::Bar() -> 0x9806008
基本上,无论调用什么,都会调用第一个虚方法。
答案 0 :(得分:3)
它只是运气好,标准中没有任何内容表明它应该有效 - 演员阵容无效。编译器很可能在内存中以完全相同的方式布置这两个类,但AFAIK没有这样的义务。
尝试添加:
virtual void Bar()
{
std::cout << "A::Bar() -> " << this << std::endl;
}
Foo
A
之前的,看看会发生什么 - 运行Bar
时可能会调用b->Foo()
。
答案 1 :(得分:1)
reinterpret_cast<>
基本上会关闭任何类型的安全检查并告诉编译器“不要检查这个,我知道我在做什么。”
Microsoft's page on reinterpret_cast告诉它以及任何人;
reinterpret_cast的结果无法安全地用于任何事情 除了被回归到原来的类型。其他用途是,在 最好,不便携。
答案 2 :(得分:0)
无效;取消引用已被强制转换为错误类型的指针会产生未定义的行为。
在这种情况下,它似乎起作用,因为两个对象都具有匹配的虚函数,并且编译器恰好以相同的方式为每个对象布置虚拟调度元数据。虽然大多数编译器可能会这样做,但它没有指定,也不能依赖。
答案 3 :(得分:0)
来自标准5.2.10 / 7
指向对象的指针可以显式转换为指向的指针 不同类型的对象.65)除了转换类型的右值 “指向T1的指针”到“指向T2的指针”(其中T1和T2为 对象类型以及T2的对齐要求为否 比T1更严格,并回到原来的类型产生 原始指针值,这种指针转换的结果是 未指定的。
这意味着唯一保证的是,如果你将A转换为B然后再回到A,你会得到原始指针:
A* a = reinterpret_cast<A*>(reinterpret_cast<B*>( new A ));
a->Foo(); //Ok
所有其他用途均未指定。