2017-02-07 9 views
0

私は、ポインタのベクトルを反復する各ループに対してaを持っています。ポインタは基本クラスへのポインタです。 for eachループでは、派生型をイテレータの型として使用します。レンダリング関数は派生クラスのいくつかでのみ定義されていますが、コードはコンパイルされて実行されます...ベクトルにレンダリング関数を持たない派生オブジェクトへのポインタが含まれているとクラッシュします。私はそれを書いたとき、ベクトルのみ派生クラスへのポインタが含まれていたが、後に、私はコードをリファクタリングすることを決定し、これが変更されたため、このエラーは私のコードでは、約来たそれぞれの隠し型キャストのためのC++

for each (DerivedClass* body in myVector) 
{ 
    body->render(); 
} 

誰も私にこのエラーをトラップする正しい方法を教えてもらえますか?ヌルポインタのチェックが機能していないようです。

+2

これはC++であると確信していますか? – SU3

+1

@ SU3は、標準の範囲ベースのforループをサポートして以来、廃止されている古いMSVC構文です。 – chris

+0

それは、ボンネットの下で 'static_cast'を実行するようなサウンドなので、事後確認はできません。 'BaseClass * 'で反復処理し、' dynamic_cast'で手動でダウンキャストする方法はありますか? – Quentin

答えて

1

私が正しく理解していれば、問題はベクトル内のポインタの一部が、render()を実装するタイプのオブジェクトを指していることにあります。その場合、dynamic_castは正しいタイプのチェックのトリックを行います。

for (DerivedClass *p : myVector) { 
    class_implementing_render *q = dynamic_cast<class_implementing_render>(p); 
    if (q) q->render(); 
} 
+0

これはテストしましたか? –

3

ここでの問題は、Microsoftのforeachループがあまりにも容認されていることです。マイクロソフトは、標準の範囲ベースのforループ(C++ 11以降)の賛成でこの拡張機能を非推奨になりました。ここで

for (DerivedClass* body : myVector) { 
    body->render(); 
} 

、ループの頭を、それはAからDerivedClass*を初期化できないため、コンパイルされませんBaseClass*

これを実際にコンパイルすることについては、まずデザインを考え直してください。実装するのではなく、インターフェイスにプログラミングする必要があります。これらのオブジェクトがレンダリング可能であるかどうかに依存することは、コードの匂いではありません。つまり、dynamic_castを通して可能だし、言った:

for (auto base : myVector) { 
    if (auto derived = dynamic_cast<DerivedClass*>(base)) { 
     derived->render(); 
    } 
} 

(私は唯一の標準的なループがないことから、想定することができます)C++ 11を持っていないのですか?従来のforループをインデックスまたはイテレータとともに使用することはできます。私のdynamic_castの例では、そのタイプについてより明確に説明することもできます。

このスピンを追加するには、このタイプのキャストが一般的な場合(たとえば、コンパイラの実装など)があります。これが良い設計選択であると判断された場合、このコードをアルゴリズムでラップすることができます。たとえば、C#での表示方法は次のとおりです。

foreach (var body in myVector.OfType<DerivedClass>()) { 
    body.render(); 
} 
関連する問題