static_castを対はdynamic_cast継承階層を横断するため
-
21-09-2019 - |
質問
私は、静的なキャストを使用して継承階層をナビゲートすると、ダイナミックキャストを使用するよりも効率的であることを言及する++ Cで一冊の本を見ます。
例:
#include <iostream>
#include <typeinfo>
using namespace std;
class Shape { public: virtual ~Shape() {}; };
class Circle : public Shape {};
class Square : public Shape {};
class Other {};
int main() {
Circle c;
Shape* s = &c; // Upcast: normal and OK
// More explicit but unnecessary:
s = static_cast<Shape*>(&c);
// (Since upcasting is such a safe and common
// operation, the cast becomes cluttering)
Circle* cp = 0;
Square* sp = 0;
// Static Navigation of class hierarchies
// requires extra type information:
if(typeid(s) == typeid(cp)) // C++ RTTI
cp = static_cast<Circle*>(s);
if(typeid(s) == typeid(sp))
sp = static_cast<Square*>(s);
if(cp != 0)
cout << "It's a circle!" << endl;
if(sp != 0)
cout << "It's a square!" << endl;
// Static navigation is ONLY an efficiency hack;
// dynamic_cast is always safer. However:
// Other* op = static_cast<Other*>(s);
// Conveniently gives an error message, while
Other* op2 = (Other*)s;
// does not
} ///:~
しかしながら、動的キャスト及びスタティックキャスト(上記実装される)の両方を必要とRTTIが機能するようなナビゲーションのために有効。これは、動的キャストが多型(すなわち、基底クラスを有する少なくとも一つの仮想関数)とクラス階層を必要とするだけということです。
静的なキャストについては、この効率のゲインはどこから来るのでしょうか?
この本は、動的キャストは、タイプセーフなダウンキャストを行うための好ましい方法であることを言及しています。
解決
static_cast
のそれ自体の必要はありませんRTTI - typeid
ん(dynamic_cast
がそうであるように)、それは完全に別の問題です。ほとんどのキャストはちょうど「私は私がやっているものを知って、私を信じて」コンパイラを言っている - dynamic_cast
は例外で、それは実行時にチェックし、おそらく失敗するようにコンパイラに要求します。それはすぐそこに大きなパフォーマンスの違いです!
他のヒント
これのの可能な場合は、すべてのタイプに切り替え避けるために、より良いの多くの。これは通常、異なるサブタイプのために異なる方法で実装される仮想メソッドに関連するコードを移動することによって行われます:
class Shape {
public:
virtual ~Shape() {};
virtual void announce() = 0; // And likewise redeclare in Circle and Square.
};
void Circle::announce() {
cout << "It's a circle!" << endl;
}
void Square::announce() {
cout << "It's a square!" << endl;
}
// Later...
s->announce();
あなたが変更できないことを、既存の継承階層を使用している場合は、調査ビジタータイプスイッチングをより拡張可能な代替のためのパターンの
の詳細情報:のstatic_cast
はのはRTTIを必要としませんが、それは未定義の動作につながる、危険なことができます使用してダウンキャストが(例えばクラッシュ)。それをチェックしRTTI情報を(したがってが必要)のでdynamic_cast
は、安全ではなく遅いです。それは静かにstatic_cast
は、コンパイル時エラーが発生したオブジェクトです完全に無関係の種類、全体にキャストされますので、古いCスタイルのキャストはさらに危険なstatic_cast
よります。
静的キャスト(およびtypeidをチェック)して、あなたがすることはできません。のダウンキャストの(父へ祖父からあなたが意気消沈することはできません祖父から父の派生から子導出し、)中間型への使用がもう少し限定されています。 typeidのチェックなしにはstatic_castをもパフォーマンスのために正確さを犠牲にされ、その後、あなたは彼らの言うことを知ってます:
の彼人犠牲正確性、パフォーマンスのために、どちらもの
値しありません次に、もちろん、あなたはいくつかのCPU命令の絶望的な必要としている状況があり、改善を探すためにどこにもあり、あなたがやっていることで、実際に安全であり、あなたはmeassuredている(右?)そのゲイン性能への唯一の場所の代わりのdynamic_castをstatic_castを使用している...そして、あなたがあなたのデザイン、またはあなたのアルゴリズムを手直しや、より良いハードウェアを取得する必要があります知っています。
あなたはRTTI +はstatic_castを使用することによって課す制限は、あなたがわずか数CPU命令を得るために、このトリックを使用しているすべての場所を作り直すことなく、後で新しい派生クラスを使用してコードを拡張することができませんということです。自分自身を再加工することは、おそらくより多くの時間あなたが取得したCPU時間よりも(より高価であるエンジニアリング時間を)取ること。 、任意の割合で、ダウンキャストに捧げた時間が顕著である場合j_random_hackerが示唆するように、そして、あなたの設計を手直し、それはデザインと性能の両方を向上させます。
dynamic_cast
はNULLを返します。 static_cast
は成功する(そして、このような最終的なクラッシュなど、未定義の動作につながる)でしょう。それはおそらく速度差です。