ビデオゲームを設計しているとしましょう。マップ上にいくつかのスプライトがあり、特定の位置で特定のスプライトのメソッドを呼び出したいと考えています。
広く知られたC++フレームワークの1つを使用しています。 GraphicsItem
クラスがあり、すべてのスプライトはこのクラスから派生しています。現在、フレームワークには、マップ上の任意の位置でGraphicsItem
のポインターを取得するメソッドがあります。
現在、2つのオプションがあります。
GraphicsItem*
からSprite*
にキャストし、Sprite
のメソッドを呼び出します。 (マップ上のすべてのグラフィックアイテムがSprite
のインスタンスであることは確かです)
クレイジーなものを作成するSprite
へのポインタをコンテナに格納し、それらを反復処理して、アドレス値を比較し、キャストせずにSprite*
を取得します。
問題は、この場合のベストプラクティスは何ですか?私はいつも型キャストを避けるように言われました、それはあなたがデザインの問題を抱えていることを意味するからです。しかし、ここで型キャストを回避するためにデザインをどのように変更できますか?そして、比較を伴うコンテナに対する追加の反復はただ...クレイジーです...
シーン内のすべてがSprite
のインスタンスであることがわかっている場合は、型キャストに問題はありません。 RTTIを有効にし、dynamic_cast<Sprite *>
を使用してさらに確実にすることができます。
GraphicsItem
のインスタンスではない他のSprite
要素がある場合は、Sprite
のインスタンスへのポインタを保持するセット(おそらくQSet<GraphicsItem *>
)を保持できますシーンに表示されるはずです。シーンからポインターを取得したら、それがスプライトのセットに含まれていることを確認してください。これには、シーン自体のメンテナンスと一緒にセットをメンテナンスする必要があるという欠点があります。
GraphicsItem *
をSprite *
にマッピングするマッピングコンテナを作成する必要はありません。
最初の基本型への暗黙的なキャストと派生型への逆静的キャストは、実行時に型がまったくゼロの操作であることが確実な場合に行われます。あなたはそれを倒すことはできません。
非最初の基本型への暗黙的なキャストと、非最初として基本を持つ派生型への逆静的キャストは、nullポインターチェックを使用した単純なインクリメント/デクリメントです。コストはかかりますが、取るに足らないことであり、ルックアップで勝つことはありません。
動的キャストは、オブジェクトから仮想メソッドテーブルポインターを読み取り、それをターゲットクラスのポインターと比較し、実際の型のベースであるものにキャストしている場合は、ポインターのチェーンに従ってチェックします。コストは少し高くなりますが、あらゆる種類のルックアップで打ち負かすことはできません。
だから、ぜひキャストしてください。タイプをチェックする必要がある場合は、動的キャストを使用してください(基本タイプが機能するには、少なくとも1つの仮想メンバーが必要ですが、ここでは確かにそうです)。
はい、型キャストする必要がある場合、実際には通常、設計上の問題があることを意味します。ただし、この場合は設計上の問題ではありません。ライブラリが、ライブラリが必要とするインターフェイスから派生した独自の基本クラスを指定する手段を提供し、それを(テンプレートを介して)返す場合、仮想メソッドを使用して、おそらくそこからビジターパターンを利用できます。残念ながらそれはできないので、キャストする必要があります。必要に応じて、キャストを行う独自のクラスでキャンバスをラップし、挿入もラップして、すべてのアイテムが実際にスプライトであることを確認できます。