1

有人能解释一下为什么下面的代码有效吗,我已经在 Visual Studio .NET 2008、Cygwin 和ideone.com上的 g++ 上进行了测试。更重要的是我想知道它是否有效。请注意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

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

4

4 回答 4

3

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

尝试添加:

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

Foo在进入之前A看看会发生什么 -运行Bar时可能会被调用b->Foo()

于 2012-03-27T10:53:48.383 回答
1

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

微软关于 reinterpret_cast 的页面和任何人一样告诉它;

reinterpret_cast 的结果除了被强制转换回其原始类型外,不能安全地用于任何事情。其他用途充其量是不可移植的。

于 2012-03-27T10:52:57.193 回答
0

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

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

于 2012-03-27T10:54:53.057 回答
0

从标准 5.2.10/7

指向对象的指针可以显式转换为指向不同类型对象的指针。65)除了将“指向 T1 的指针”类型的右值转换为“指向 T2 的指针”类型(其中 T1 和 T2 是对象类型和在 T2 的对齐要求不比 T1 严格的情况下,返回其原始类型会产生原始指针值,这种指针转换的结果是未指定的。

What this means is that the only thing that's guaranteed is that if you cast A to B and then back to A you get the original pointer back:

  A* a = reinterpret_cast<A*>(reinterpret_cast<B*>( new A ));
  a->Foo();  //Ok

All other uses are unspecified.

于 2012-03-27T10:56:19.750 回答