2009-03-07 8 views
3

J'ai une classe avec une méthode statique qui ressemble à peu près comme:Problème appeler une fonction quand il est dans un .lib

class X { 
    static float getFloat(MyBase& obj) { 
     return obj.value(); // MyBase::value() is virtual 
    } 
}; 

J'appelle avec une instance de MyDerived qui MyBase sous-classes:

MyDerived d; 
float f = X::getFloat(d); 

Si je lier le fichier obj contenant X dans mon exécutable, tout fonctionne comme prévu. Si je m'attends à obtenir 3,14, je comprends.

Si je crée un fichier .lib contenant le fichier X.obj et le lien dans le fichier .lib, il se casse. Quand j'appelle getFloat(), il renvoie -1. # IND00. Est-ce une sorte de valeur sentinelle qui devrait me dire ce qui ne va pas ici?

Est-ce que quelque chose est différent quand vous liez dans un lib plutôt que dans un obj directement?

Je ne reçois aucun avertissement ou erreur du compilateur.

Edit:
J'utilise Visual Studio 2005 sous Windows XP Pro SP3. Pour m'assurer que je ne liais pas les anciens fichiers, j'ai cloné la méthode value() dans une nouvelle méthode value2() et l'ai appelée à la place. Le comportement était le même.

Edit # 2:
Donc, si je trace dans l'appel avec mon débogueur, je trouve qu'il ne va pas dans ma méthode de la valeur() du tout. Au lieu de cela, il va dans une méthode différente (non liée). Cela me fait penser que mon vtable est corrompu. Je pense que le comportement que je vois doit être un effet secondaire d'un autre problème.


Résolu! (merci à Vlad)
Il s'avère que je violais la règle de définition unique (ODR), bien que ce n'était pas évident à partir du code que j'ai posté. This est un excellent article des gars de Visual C++ qui explique le problème et un moyen de le retrouver. L'indicateur de compilateur /d1reportSingleClassLayout est un outil d'apprentissage fantastique.

Lorsque j'ai supprimé la mise en page de ma classe pour MyBase et MyDerived dans les deux projets différents, j'ai trouvé des différences entre le code appelant et le code de la bibliothèque. Il s'est avéré que j'avais des blocs #ifdef dans mes fichiers d'en-tête et l'instruction #define correspondante était dans l'en-tête précompilé pour le projet principal mais pas dans le sous-projet (la bibliothèque). Ai-je mentionné à quel point les macros du préprocesseur sont mauvaises?

Quoi qu'il en soit, je ne poste que ce genre de choses, car cela pourrait être utile à quelqu'un d'autre. This question était aussi très utile pour moi.

+0

Quelle plateforme? Quel système de développement? Cela compte. – jmucchiello

+1

Ne pas écrire des solutions dans les questions, s'il vous plaît. –

Répondre

1

Ce problème se produit lorsque le répertoire lib et l'exécutable ont été être compilé avec différentes définitions des MyDerived classe (versions-à-dire différentes de la .h/.hh/fichier .hpp qui déclare MyDerived. Complètement propre et reconstruire vos projets. sauf cela, les différentes options du compilateur pourrait être responsable, mais il est plutôt improbable.

Si le problème persiste après la reconstruction de tout à partir de zéro, puis clouez par instanciation d'un objet MyDerived factice à l'intérieur getFloat, dans la bibliothèque. Utilisez le débogueur pour comparer le vtable du mannequin MyDerived (instancié dans la bibliothèque) et le vtable de la référence d'objet MyDerived passée en paramètre (instancié dans l'exécutable.) Quelque chose devrait immédiatement se mettre en évidence.

+0

Vous avez tout à fait raison! J'utilise le compilateur de Microsoft et il a un drapeau pour vider la disposition de classe. De cela, j'ai trouvé les différences. Merci beaucoup pour votre aide. – criddell

0

Il ne devrait pas y avoir de différence. Assurez-vous simplement que les fichiers .h que vous avez inclus correspondent au fichier .lib auquel vous vous connectez exactement. Je suppose que vous pouvez être lié à un ancien fichier .lib.

Si vous utilisez Visual Studio, au lieu de spécifier explicitement le fichier .lib, faites simplement un clic droit sur le projet et définissez les dépendances dans le projet .lib. De cette façon, vous serez sûr qu'il utilise le bon fichier .lib.

+0

Je charge la bibliothèque avec un "#pragma comment (lib," mylib ")". Je m'inquiétais aussi de lier les anciens fichiers, donc j'ai copié la méthode dans un nouveau nom (mais avec le même contenu) et j'ai appelé cette méthode sans changement de comportement. – criddell

1

Puisqu'un lib est juste un conteneur, si vous liez le même.obj dans les deux cas alors que Brian dit qu'ils ne devraient pas (ne peuvent pas?) être une différence. Une chose à surveiller est que si vous avez changé la définition de MyBase, vous devez évidemment recompiler à la fois la bibliothèque et le code qui l'utilise. Par exemple, si vous avez ajouté une nouvelle méthode virtuelle à MyBase avant la méthode value, cela gâcherait la bibliothèque car le décalage de la valeur de la table v serait différent.

Questions connexes