RTTI が悪い設計と見なされる理由は何ですか?
Stroustrup は彼の著書 TC++PL の中で、最も一般的な RTTI テクニックの使用例は、渡されたオブジェクトの「実際の」型に基づいて実行すべきコードを決定したい場合に switch 命令を使用することであると書いています。形状クラスのオブジェクトが関数に渡され、形状が円、正方形、三角形などによって異なるアクションが実行される例が示されています。仮想関数による switch-case シーケンス。
1 に答える
RTTI は、クラスに仮想テーブルがある場合にのみ機能します。仮想テーブルがある場合は、仮想関数を実装できます。オブジェクトの型のスイッチではなく仮想関数を使用する必要がある理由は、継承チェーンでより適切に機能し、新しいクラスを追加するときに脆弱性が少ないためです。
例えば:
class A : public V {}
class B : public V{}
void do_something( const V & v )
{
if (typeid(A) == typeid(v)) { .. its an A .. }
if (typeid(B) == typeid(v)) { .. its a B .. }
}
int main()
{
do_something( A() );
do_something( B() );
}
C
から派生した新しいクラスを追加して、(の実装を変更せずに)V
を呼び出しても、何も起こりません。(コンパイル時にエラーは発生しません)。から派生したクラスを追加しても、エラーは発生せず、何も起こりません。do_something( C() )
do_something
D
A
これを仮想関数の動作と比較してください
struct V
{
virtual void do_something() const =0;
};
struct A
{
virtual void do_something() const { ... its an A ... }
}
struct B
{
virtual void do_somethine() const { ... its a B ... }
}
void do_something( const V & v )
{
v.do_something();
}
から派生C
しV
て実装しないとC::do_something()
、コンパイル時エラーが発生します。から派生D
しA
、実装しない場合は、 へのD::do_something()
呼び出しが発生しA::do_something()
ます。
したがって、これが RTTI よりも仮想機能が好まれる主な理由です。ただし、 の動作がまたはクラスdo_something
に属していないと感じる場合があります。そのため、RTTI を (またはで) 使用したくなるでしょう。多くの場合、より良い解決策は、クラス階層にビジター パターンを実装することです。V
A B C
typeid
dynamic_cast