interpret_cast和virtual在不相关的类型之间

reinterpret_cast and virtual between unrelated types

本文关键字:不相关 类型 之间 virtual cast interpret      更新时间:2023-10-16

有人能解释一下为什么下面的代码有效吗?我已经在Visual Studio.NET 2008、Cygwin和ideone.com上测试过它。更重要的是,我想知道它是否有效。注意,AB是不相关的类型。

编辑:跟随@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

基本上,无论调用什么,都会调用第一个虚拟方法。

它只是运气好,标准中没有任何内容表明它应该工作——强制转换无效。编译器可能会在内存中以完全相同的方式布置两个类,但不存在AFAIK这样的义务。

尝试添加:

virtual void Bar()
{
    std::cout << "A::Bar() -> " << this << std::endl;
}

A中的Foo之前,看看会发生什么——b->Foo()运行时很可能会调用Bar

reinterpret_cast<>基本上关闭任何类型的安全检查,并告诉编译器"不要检查这个,我知道我在做什么。"

微软在relpret_cast上的页面告诉它和任何人一样好;

interpret_cast的结果不能安全地用于任何事情而不是被铸造回其原始类型。其他用途包括,在最好,不可移植。

无效;取消引用被强制转换为错误类型的指针会产生未定义的行为。

在这种情况下,它似乎可以工作,因为两个对象都有匹配的虚拟函数,而编译器恰好以相同的方式为每个对象布置虚拟调度元数据。虽然大多数编译器可能都会这样做,但它没有指定,也不能依赖。

来自标准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

所有其他用途均未指明。