10

私はC++で次のケースを持っています:

  • 抽象基本クラスAbstract1Abstract2. それらは無関係です。
  • とのFoo両方から派生するクラスAbstract1Abstract2

私は、クラスに関する情報がないFoo(宣言も定義もない) コンパイル ユニットにいます。Abstract1とのみAbstract2が知られています。(実際、Foo は DLL でも定義されています)

dynamic_cast は からAbstract1*へのキャストを許可しAbstract2*ますか? これは標準ですか?

4

4 に答える 4

6

あなたが説明するのは、いわゆるクロスキャストです。の場合dynamic_cast<T>(v)、標準は [expr.dynamic.cast]/8 で指定します

Cがポイントまたは参照先のクラス型である場合T、実行時チェックは次のように論理的に実行されます。

  • が指す (参照する) 最も派生したオブジェクトで、オブジェクトのパブリック基本クラス サブオブジェクトvv指す (参照する)C場合 [..]

  • それ以外の場合、が最も派生したオブジェクトの基底クラス サブオブジェクトvを指し (参照し) public、最も派生したオブジェクトの型が型 の基底クラスを持ちC、それが明確であり、 である場合、結果は のサブオブジェクトをpublic指します (参照します) 。C最も派生したオブジェクト。

Fooこれは、キャストを含む翻訳単位に が存在するという情報がなくても機能します。

この質問もチェックする必要があります。

于 2014-11-20T14:38:21.873 に答える
4

はい、動作します。

dynamic_castRTTIに基づいています。ここで RTTI によって提供される情報は、指定されたオブジェクトの実際の動的タイプを判別するのに十分です。定義上、RTTI は実行時の概念であり、指定されたオブジェクトの動的型と同様です (上記のキャストが記述されているコンパイル ユニットで Foo の定義が利用できないという事実はコンパイル時の概念であり、ここでは関係ありません)。

  • 指しているオブジェクトが実際に Foo である場合、dynamic_cast は実行時に成功します。
  • Abstract2 から派生したオブジェクトへのポインターでない場合、失敗します (null ポインターを返します)。

詳細

の可能な実装はdynamic_cast、オブジェクトのメモリ レイアウトの先頭にある特別なメンバーを検索することです (または v テーブルに沿って格納できます)。この構造体には、オブジェクトの動的タイプを識別する値を含めることができます。どこかで、コンパイラは静的テーブルを生成し、プログラム継承図に関するすべての情報を複製します。実行時に、キャストはインスタンスの型識別子を抽出し、それを静的テーブルと照合します。この識別子が Abstract2 から派生した型を参照している場合、キャストは意味があります (そして、コードはAbstract2オブジェクトのインターフェイスへの正しいオフセット ポインターを返すことができます)。

この素朴な実装でさえFoo、キャストが書かれているコンパイル単位の知識を必要としません。

于 2014-11-20T14:36:09.000 に答える
2

このコードの場合:

void func(Abstract1* a1)
{
    Abstract2* a2 = dynamic_cast<Abstract2*>(a1);
    ...
}

あなたは尋ねています:

a1がオブジェクトを指している場合Foo、動的キャストは有効なオブジェクト ポインターを返しますか?

答えはイエスです:

  • 実行時に、ダイナミック キャストは の V-Table を の V-Tablea1として識別しclass Fooます。
  • からclass Foo継承してclass Abstract2いるため、動的キャストは有効なポインターを返します。
于 2014-11-20T14:42:25.397 に答える
1

まあ、あなたはそれを試すことができたでしょう!

#include <cassert>

struct IBase1
{
    virtual void foo() = 0;
    virtual ~IBase1() {}
};

struct IBase2
{
    virtual void bar() = 0;
    virtual ~IBase2() {}
};

struct Derived : IBase1, IBase2
{
    void foo() {}
    void bar() {}
};

int main()
{
    Derived d;

    IBase1* ptr = &d;
    assert(dynamic_cast<IBase2*>(ptr));
    assert(dynamic_cast<Derived*>(ptr));
}

// Compiles successfully

そして、ここに証拠があります:

[C++11: 5.2.7/8]:Cがポイントまたは参照先のクラス型である場合T、実行時チェックは次のように論理的に実行されます。

  • が指す (参照する) 最も派生したオブジェクトで、オブジェクトの基底クラス サブオブジェクトを指す (参照する)場合v、および結果ポイント (参照する) が指す (参照する) サブオブジェクトからタイプのオブジェクトが 1 つだけ派生する場合) そのオブジェクトに。vpublicCCvC
  • それ以外の場合、v最も派生したオブジェクトのパブリック基本クラス サブオブジェクトをポイント (参照) し、最も派生したオブジェクトの型が型 の基本クラスを持っている場合C、それは明確であり、 のサブオブジェクトをpublicポイント (参照) します。C最も派生したオブジェクト。

  • それ以外の場合、ランタイム チェックは失敗します

口語的に、これをクロスキャスティングと呼びます。

最も派生したオブジェクトのタイプが「現在の」翻訳単位で知られているという言語によって規定されている要件はありません。それを機能させるのは実装次第であり、一般的な「仮想テーブル」モデルでは実際に機能します。

于 2014-11-20T14:39:04.830 に答える