33

私は C++ プログラミング クラスを教えており、一般的な C++ バグを診断する方法については十分なエラー クラスを見てきました。ただし、私の直感があまりよくない主要なタイプのエラーが 1 つあります。純粋仮想関数の呼び出しの原因となるプログラミング エラーは何ですか? これを引き起こす最も一般的なエラーは、基本クラスのコンストラクターまたはデストラクターから仮想関数を呼び出すことです。学生のコードのデバッグを支援する際に注意すべきことは他にありますか?

4

3 に答える 3

28

「これを引き起こす最も一般的なエラーは、基本クラスのコンストラクターまたはデストラクターから仮想関数を呼び出すことです。」

オブジェクトが構築されると、仮想ディスパッチ テーブルへのポインタは最初に最上位のスーパークラスを対象とし、中間クラスの構築が完了するまで更新されません。そのため、サブクラス (独自のオーバーライド関数実装を含む) が構築を完了するまで、誤って純粋仮想実装を呼び出すことができます。それは、最も派生したサブクラス、またはその中間のサブクラスである可能性があります。

部分的に構築されたオブジェクトへのポインターをたどった場合に発生する可能性があります (たとえば、非同期またはスレッド操作による競合状態)。

コンパイラが基本クラスへのポインタが指す実際の型を知っていると考える理由がある場合、コンパイラは仮想ディスパッチを合理的にバイパスする可能性があります。再解釈キャストのような未定義の動作を行うと、混乱する可能性があります。

破棄中は、派生クラスが破棄されるときに仮想ディスパッチ テーブルを元に戻す必要があるため、純粋な仮想実装が再び呼び出される可能性があります。

破棄後、「ダングリング」ポインターまたは参照を介してオブジェクトを継続して使用すると、純粋仮想関数が呼び出される場合がありますが、そのような状況での動作は定義されていません。

于 2011-01-06T08:59:17.353 に答える
8

純粋な仮想呼び出しが発生する可能性があるいくつかのケースを次に示します。

  1. ダングリング ポインターの使用 - ポインターは有効なオブジェクトではないため、ポインターが指す仮想テーブルは単なるランダム メモリであり、NULL を含む可能性があります
  2. 間違った型 (または C スタイルのキャスト) への不適切なキャストを使用するstatic_castと、指定したオブジェクトの仮想テーブルに正しいメソッドが含まれていない可能性もあります (この場合、少なくとも前のオプションとは異なり、実際には仮想テーブルです)。 .
  3. DLL がアンロードされました- 保持しているオブジェクトが、再びアンロードされた共有オブジェクト ファイル (DLL、つまり sl) で作成された場合、メモリをゼロにすることができます。
于 2011-01-06T07:32:19.210 に答える
0

これは、たとえば、オブジェクトへの参照またはポインターが NULL の場所を指しており、オブジェクト参照またはポインターを使用してクラス内の仮想関数を呼び出す場合に発生する可能性があります。例えば:

std::vector <DerivedClass> objContainer;  
if (!objContainer.empty()) 
   const BaseClass& objRef = objContainer.front();  
// Do some processing using objRef and then you erase the first
// element of objContainer
objContainer.erase(objContainer.begin());   
const std::string& name = objRef.name();  
// -> (name() is a pure virtual function in base class, 
// which has been implemented in DerivedClass).

この時点で objContainer[0] に格納されているオブジェクトは存在しません。仮想テーブルにインデックスが作成されると、有効なメモリ ロケーションが見つかりません。したがって、「純粋な仮想関数が呼び出されました」という実行時エラーが発行されます。

于 2011-07-22T15:48:58.337 に答える