2009-03-07 10 views
3

のときに関数を呼び出す:問題、それは私がおおよそ次のようになります静的メソッドを持つクラスを持っているの.lib

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を得ることを期待しているなら、私はそれを得る。

.libにX.objファイルとリンクが含まれている.libを作成してリンクすると、ブレークします。 getFloat()を呼び出すと、-1を返します。#IND00。これは、ここで何が間違っているのかを教えてくれるセンチネルの価値ですか?

objではなくlibを直接リンクするときは何か異なりますか?

コンパイラの警告やエラーは発生しません。

編集:
Windows XP Pro SP3でVisual Studio 2005を使用しています。私が古いファイルをリンクしていないことを確認するために、私はvalue()メソッドを新しいvalue2()メソッドにクローン化し、代わりにそれを呼び出しました。行動は同じでした。

編集#2:私は私のデバッガとのコールにトレースする場合
ので、私はそれがすべての私の値()メソッドに行っていないことを発見しています。代わりに、それは別の(無関係な)方法に行きます。これは私のvtableが壊れていると思う。私が見ている行動は、他のいくつかの問題の副作用でなければならないと思います。


解決済み!(Vladに感謝)
私が掲示したコードからは明らかではありませんが、私は1つの定義ルール(ODR)に違反していました。 Thisは、問題を説明するVisual C++の人からの素晴らしい記事であり、問​​題を追跡する方法の1つです。 /d1reportSingleClassLayoutコンパイラフラグは素晴らしい学習ツールです。

MyBaseとMyDerivedのMyクラスレイアウトを2つの異なるプロジェクトにダンプしたとき、私は呼び出しコードとライブラリコードの違いを発見しました。私のヘッダーファイルには #ifdefブロックがあり、対応する #defineステートメントは、メインプロジェクトのプリコンパイル済みヘッダーにありましたが、サブプロジェクト(ライブラリ)にはありませんでした。私はプリプロセッサマクロがいかに悪いと思いますか?

とにかく、私は誰かに役立つかもしれないので、この資料を投稿しています。 This questionも私にとってとても役に立ちました。

+0

どのプラットフォームですか?どのような開発システムですか?それは重要です。 – jmucchiello

+1

質問で解決策を書いてはいけません。 –

答えて

1

libと実行ファイルが完全にクリーンな。MyDerivedを宣言.h/.hh/.hppファイルのMyDerivedクラス(すなわち、異なるバージョンの異なる定義してコンパイルし、プロジェクトを再構築することされている場合、この問題が発生します。それはややそうですが、この除けば、異なるコンパイラオプション、責任を負うことができます。

を問題は最初からすべてを再構築した後に解消されない場合は、その後、getFloatの内側にダミーMyDerivedオブジェクトをインスタンス化することによって、それを爪、図書館で。デバッガを使用して、MyDerived(ライブラリでインスタンス化された)のvtableと、パラメータとして渡されたMyDerivedオブジェクト参照のvtable(実行可能ファイルでインスタンス化されます)を比較してください。

+0

あなたはまさに正しいです!私はMicrosoftのコンパイラを使用しており、クラスレイアウトをダンプするフラグがあります。これから私は違いを見つけました。助けてくれてありがとう。 – criddell

0

違いはありません。あなたが含んでいる.hファイルが、正確にリンクしている.libに対応していることを確認してください。あなたが古い.libファイルにリンクしている可能性があります。

Visual Studioを使用している場合は、.libファイルを明示的に指定するのではなく、プロジェクトを右クリックして.libプロジェクトの依存関係を設定するだけです。そうすれば、正しい.libファイルが使用されます。

+0

"#pragma comment(lib、" mylib ")"をライブラリにロードしています。私は古いファイルをリンクすることにも心配していました。そのため、メソッドを新しい名前(しかし同じ内容)の新しいファイルにコピーし、そのメソッドを動作の変更なしで呼び出しました。 – criddell

1

libは同じものをリンクしているので、単なるコンテナです。objファイルを両方のケースで使用すると、ブライアンは彼らに違いはないはずだと言います(違いはありません)。

MyBaseの定義を変更した場合、明らかにライブラリとコードの両方を再コンパイルする必要があります。たとえば、値メソッドの前に新しい仮想メソッドをMyBaseに追加した場合、値のvテーブルのオフセットが異なるため、ライブラリが壊れてしまいます。

関連する問題