1

次のコードが機能する理由を誰かが親切に説明してくれませんか? 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

基本的に、最初の仮想メソッドは、それが何と呼ばれるかに関係なく呼び出されます。

4

4 に答える 4

3

それは運が良かっただけで、標準ではそれが機能するはずだとは何も言っていません-キャストは無効です。コンパイラは両方のクラスをメモリ内でまったく同じようにレイアウトする可能性がありますが、そのような義務はありません。

追加してみてください:

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

FooA、何が起こるかを確認してください-が実行されると、チャンスがBar呼び出されb->Foo()ます。

于 2012-03-27T10:53:48.383 に答える
1

reinterpret_cast<>基本的に、型安全性チェックをオフにし、コンパイラに「これをチェックしないでください。私が何をしているのか知っています」と伝えます。

reinterpret_castに関するMicrosoftのページは、誰と同じようにそれを伝えています。

reinterpret_castの結果は、元のタイプにキャストバックする以外の目的で安全に使用することはできません。他の用途は、せいぜい、移植性がありません。

于 2012-03-27T10:52:57.193 に答える
0

無効です。間違ったタイプにキャストされたポインターを間接参照すると、未定義の動作が発生します。

この場合、両方のオブジェクトに一致する仮想関数があり、コンパイラーが各オブジェクトに対して同じ方法で仮想ディスパッチメタデータをレイアウトするため、機能しているように見えます。ほとんどのコンパイラがそれを行う可能性がありますが、それは指定されておらず、信頼できません。

于 2012-03-27T10:54:53.057 に答える
0

標準5.2.10/7から

オブジェクトへのポインタは、異なるタイプのオブジェクトへのポインタに明示的に変換できます。65)タイプ「pointertoT1」の右辺値をタイプ「pointertoT2」に変換する場合を除きます(T1とT2はオブジェクトタイプであり、 T2のアラインメント要件がT1)のアラインメント要件よりも厳密ではなく、元のタイプに戻ると元のポインター値が生成される場合、そのようなポインター変換の結果は指定されていません。

これが意味するのは、AをBにキャストしてからAに戻すと、元のポインタが返されるということだけが保証されているということです。

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

他のすべての用途は指定されていません。

于 2012-03-27T10:56:19.750 に答える