【问题标题】:reinterpret_cast and virtual between unrelated types不相关类型之间的 reinterpret_cast 和 virtual
【发布时间】:2012-04-10 21:35:28
【问题描述】:

有人能解释一下为什么下面的代码可以工作吗,我已经在 Visual Studio .NET 2008、Cygwin 上的 g++ 和 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

基本上不管调用什么,都会调用第一个虚方法。

【问题讨论】:

  • 当您将 A::Foo 重命名为 A::Bar 并保留其他所有内容时,我想它甚至“有效”?

标签: c++ virtual reinterpret-cast


【解决方案1】:

它只是靠运气,标准中没有任何内容说它应该工作 - 演员表无效。编译器可能会以完全相同的方式在内存中布置这两个类,但 AFAIK 没有这样的义务。

尝试添加:

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

A 中的Foo 之前,看看会发生什么-Bar 很可能会在b-&gt;Foo() 运行时被调用。

【讨论】:

    【解决方案2】:

    reinterpret_cast&lt;&gt; 基本上关闭任何类型安全检查并告诉编译器“不要检查这个,我知道我在做什么。”

    Microsoft's page on reinterpret_cast 和任何人一样告诉它;

    reinterpret_cast 的结果不能安全地用于任何事情 除了被转换回原来的类型。其他用途是,在 最好的,非便携的。

    【讨论】:

    • 虽然在某些特殊情况下,reinterpret_cast 实际上标准保证以某种特定方式运行,例如std::complex&lt;double&gt; z(1.,2.); double* a=reinterpret_cast&lt;double*&gt;(&amp;z); std::cout &lt;&lt; a[0] &lt;&lt; ", " &lt;&lt; a[1]; 将始终打印z 的实部和虚部。
    • @leftaroundabout 不,不必。阅读标准中的第 5.2.10 节。
    • @AndreasBrinck:是的 (C++11 26.4.4)。
    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

      从标准 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
      

      未指定所有其他用途。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-02-19
        • 2020-02-14
        • 1970-01-01
        • 2021-11-23
        • 2019-02-06
        • 2016-03-15
        • 2013-08-02
        • 1970-01-01
        相关资源
        最近更新 更多