おおよそ次のような静的メソッドを持つクラスがあります。
class X {
static float getFloat(MyBase& obj) {
return obj.value(); // MyBase::value() is virtual
}
};
MyBase をサブクラス化する MyDerived のインスタンスで呼び出しています。
MyDerived d;
float f = X::getFloat(d);
X を含む obj ファイルを実行可能ファイルにリンクすると、すべてが期待どおりに機能します。私が 3.14 を期待しているなら、私はそれを手に入れました。
X.obj ファイルを含む .lib を作成し、.lib にリンクすると、壊れます。getFloat() を呼び出すと、-1.#IND00 が返されます。これは、ここで何が問題なのかを教えてくれるセンチネル値のようなものですか?
obj を直接リンクするのではなく、lib をリンクすると何か違いはありますか?
コンパイラの警告やエラーは表示されません。
編集:
Windows XP Pro SP3 で Visual Studio 2005 を使用しています。古いファイルをリンクしていないことを確認するために、value() メソッドを新しい value2() メソッドに複製し、代わりにそれを呼び出しました。動作は同じでした。
編集 #2:
したがって、デバッガーで呼び出しをトレースすると、それが value() メソッドにまったく入っていないことがわかります。代わりに、別の (無関係な) メソッドに入ります。これにより、vtable が破損していると思われます。私が見ている動作は、他の問題の副作用であるに違いないと思います。
解決しました!(Vlad に感謝)
投稿したコードからは明らかではありませんでしたが、1 つの定義規則 (ODR) に違反していたことが判明しました。これは Visual C++ 関係者による素晴らしい記事で、問題とその追跡方法の 1 つを説明しています。/d1reportSingleClassLayoutコンパイラフラグは素晴らしい学習ツールです。
2 つの異なるプロジェクトで MyBase と MyDerived のクラス レイアウトをダンプしたところ、呼び出しコードとライブラリ コードの間に違いがあることがわかりました。ヘッダー ファイルにいくつかの#ifdefブロックがあり、対応する#defineステートメントがメイン プロジェクトのプリコンパイル済みヘッダーにありましたが、サブプロジェクト (ライブラリ) にはありませんでした。プリプロセッサ マクロがいかに邪悪であるかについて言及しましたか?
とにかく、他の誰かに役立つかもしれないので、私はこのものを投稿しているだけです. この質問もとても参考になりました。