18

次の場合:

class Animal{};

class Bird : public Animal{};

class Dog : public Animal{};

class Penguin : public Bird{};

class Poodle : public Dog{};

dynamic_castあるクラスが別のクラスの派生クラスであるかどうか、またはあるクラスが別のクラスの基本クラスであるかどうかを確認するだけですか?だから私が持っていた場合:

Bird* bird;
Animal* animal;

bird = dynamic_cast<Animal*>(bird);
animal = dynamic_cast<Bird*>(animal);

birdAnimalこれでクラスを指すようになり、使用できるようになり、 ?bird->some_function();で関数が呼び出されます。Animalそして今、クラスをanimal指しているので、私はそれを行うことができ、それは呼び出されますか?Birdanimal->some_function();some_function();Bird

私はどのようにdynamic_cast機能するかを理解しようとしてきましたが、オンラインで見つけたリソースはあまり役に立ちませんでした。誰かがその機能とそれが役立つであろういくつかの例について他の洞察を提供することができればdynamic_cast、私はそれを高く評価します。

4

4 に答える 4

18

ダイナミックキャストで最も重要なことは、に適用する必要があるということpolymorphic typeです。それがないと、動的キャストは静的キャストのように機能します。

ポリモーフィックタイプとは何ですか?少なくとも1つの仮想メソッド、仮想デストラクタ、または仮想基本クラスを持つクラスはすべてポリモーフィックです。これらのタイプのみが、データレイアウトに仮想メソッドテーブル(VMT)を持っています。仮想を持たないクラスにはVMTがありません。この標準では、ポリモーフィズムと仮想メソッドをどのように実装するかについては規定されていませんが、私が知る限り、すべてのコンパイラーがこれを実行しています。

あなたの例では、クラスはポリモーフィックではありません。私の意見では、動的キャストが非ポリモーフィック型に適用されたときにコンパイラーがエラーを発行する方がよいでしょう。それにもかかわらず、彼らはこれをしません。これは混乱を助長します。

すべてのクラスのVMTポインターは異なります。これは、ランタイムで次のことを確認していることを意味します。

Animal* animal;

オブジェクトの実際のクラスが何であるかを知ることができます。それはaBirdまたはaDogまたは何か他のものですか。VMTの値から実際のタイプを知ることで、生成されたコードは、これが必要な場合に調整を行うことができます。

次に例を示します。

class Animal   { virtual ~Animal();   int m1; };
class Creature { virtual ~Creature(); int m2; };

class Bird : public Animal, Creature { };

Bird *bird = new Bird();
Creature *creature = dynamic_cast<Creature*>(bird);

クリーチャーは一塁クラスではないことに注意してください。これは、オブジェクトの右側を指すようにポインタがシフトされることを意味します。それでも、次の機能は引き続き機能します。

Animal *animal = dynamic_cast<Animal*>(creature);   // Case2.

他のクラスの一部である場合のクリーチャーのVMTは、スタンドアロンで使用される場合のオブジェクトのVMTと同じではないためです。

Creature *creature1 = new Creature();

この区別により、動的キャストの適切な実装が可能になります。この例Case2では、ポインタが後ろにシフトされます。私はこれをテストしました。これは機能します。

于 2012-12-09T00:26:33.787 に答える
10

オペレーターは、ポインターが指す実際のオブジェクトのdynamic_castタイプをチェックします。これがコンパイル時との違いです。の結果はランタイムデータに依存します。static_castdynamic_cast

dynamic_cast<Animal*>(bird)

上記の場合、AnimalはのスーパークラスであるBirdためdynamic_cast、ここでは必要ありません(コンパイラは、キャストをキャストしないか、キャストしない場合と同じように扱いstatic_castます)。

dynamic_cast<Bird*>(animal)

この場合、このステートメントが実際に実行されると、ランタイムシステムは、実際animalに指しているオブジェクトの種類に関係なく、実際のタイプを検査します。Birdのまたはサブクラスである可能性があります。Birdその場合、結果は有効になりますBird*。オブジェクトが。でない場合Bird、結果は。になりますNULL

dynamic_castこれらの呼び出しの結果を元のポインターに割り当てるという事実によって、質問はさらに複雑になります。これはおそらく混乱の一部が原因であるため、上記の説明からこの側面を省略しました。

于 2012-12-09T00:28:06.500 に答える
5

あなたがそれを置くとき、これはあまり意味がありません。

ポイントはdynamic_cast、実行時にポリモーフィズムを解決することです。したがって、実際の興味深いシナリオは次のようになります。

void animalhandler(Animal& animal);

ただし、これは少なくとも)のインスタンスでAnimalはなく、サブクラスのいずれかで呼び出されます。多くの場合、知る必要はありません。の仮想メンバーを呼び出すことができ、派生クラスが実際に属しているanimalものに関係なく、C++が正しいオーバーロードを呼び出すようにすることができます。*animal

ただし、特定の派生インスタンスでのみ可能なことを実行したい場合があります。その場合、次dynamic_castのように使用します

void animalhandler(Animal& animal) {
  if(auto as_bird = dynamic_cast<Bird*>(&animal)) {
    // bird-specific code
  }
}

ここで、が実際にa (またはから派生)であるif場合にのみ起動します。それ以外の場合は、と解釈されるjustが返されます。animalBirdBirddynamic_castnullptriffalse

今、あなたは反対のことをするという考えを思いつきます。これがどのようになるか見てみましょう:

  if(auto as_bird = dynamic_cast<Bird*>(&animal)) {
    if(auto as_animal = dynamic_cast<Animal*>(as_bird)) {
      // animal-specific code
    }
  }

...待ってください、それは動物特有のものであるという意味ですか?いいえ、すべて BirdAnimalsであるため、コンパイル時に動的にチェックする意味がないことがわかっています。あなたはまだそれを書くことができます、しかしそれはそうas_birdするすべてのメンバーへのアクセスを与えるので、あなたはそれを省いて直接使うほうがよいas_animalでしょう。

于 2012-12-09T00:27:25.573 に答える
0

C++ワーキングドラフトから

ダイナミックキャスト[expr.dynamic.cast]

1式dynamic_cast<T>(v)の結果は、式vを型Tに変換した結果です。Tは、完全なクラス型へのポインターまたは参照、または「cvvoidへのポインター」でなければなりません。dynamic_cast演算子は、constness(5.2.11)をキャストしてはなりません。

6それ以外の場合、vはポリモーフィック型(10.3)へのポインタまたは左辺値でなければなりません。

8 CがTが指すまたは参照するクラスタイプである場合、ランタイムチェックは論理的に次のように実行されます。
-vが指す(参照する)最も派生したオブジェクトで、vがパブリックベースクラスを指す(参照する)場合Cオブジェクトのサブオブジェクトであり、タイプCの1つのオブジェクトのみがvによってポイントされる(参照される)サブオブジェクトから派生する場合、結果はそのCオブジェクトを指す(参照する)。
-それ以外の場合、vが最も派生したオブジェクトのパブリック基本クラスサブオブジェクトを指し(参照)、最も派生したオブジェクトのタイプがタイプCの基本クラスを持ち、明確でパブリックである場合、結果はポイント(参照)します。最も派生したオブジェクトのCサブオブジェクトに。
-それ以外の場合、実行時チェックは失敗します。

これらの条項から結論できること

  • dynamic_cast多形クラスで動作します
  • に向けられた(または参照された)オブジェクトで実行時を調べます
  • キャストが成功するか失敗するか、ポイントされたオブジェクトのパブリックベースクラスに基づいて決定します
于 2012-12-09T00:40:15.663 に答える