我有一个静态方法的类看起来大致如下:

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

我用MyDerived的一个实例调用它,它是MyBase的子类:

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

如果我将包含X的obj文件链接到我的可执行文件中,一切都按预期工作。如果我期望得到3.14,我就明白了。

如果我创建一个包含.lib中的X.obj文件和链接的.lib,它会中断。当我调用getFloat()时,它返回 -1。#IND00 。这是某种类型的哨兵值,应该告诉我这里有什么问题吗?

当你直接链接lib而不是obj时,有什么不同吗?

我没有收到任何编译器警告或错误。

修改的结果, 我在Windows XP Pro SP3上使用Visual Studio 2005。为了确保我没有链接旧文件,我将value()方法克隆到一个新的value2()方法中并调用它。行为是一样的。

编辑#2:
所以,如果我使用我的调试器跟踪调用,我发现它根本不会进入我的value()方法。相反,它将进入一个不同的(不相关的)方法。这让我觉得我的vtable已经损坏了。我认为我所看到的行为必然是其他一些问题的副作用。


解决了!(感谢Vlad)
事实证明我违反了一个定义规则(ODR),尽管从我发布的代码中看不出来。 这是一篇来自Visual C ++人员的精彩文章,它解释了问题以及追踪它的一种方法。 / d1reportSingleClassLayout 编译器标志是一个很棒的学习工具。

当我在两个不同的项目中抛弃MyBase和MyDerived的我的类布局时,我发现调用代码和库代码之间存在差异。事实证明我的头文件中有一些 #ifdef 块,相应的 #define 语句位于主项目的预编译头中,但不在子项目中(库中) )。我是否曾提到我认为预处理器宏是多么邪恶?

无论如何,我只发布这些东西,因为它可能对其他人有帮助。 这个问题对我也很有帮助。

有帮助吗?

解决方案

当使用 MyDerived 的不同定义(即 .h <的不同版本)编译lib和可执行文件时,会发生此问题。 / code> / .hh / .hpp 文件声明 MyDerived 。完全清理并重建你的项目。除此之外,不同的编译器选项可能负责,尽管有点不太可能。

如果从头开始重建所有内容后问题仍然存在,那么通过在库中实例化 getFloat 中的虚拟 MyDerived 对象来确定它。使用调试器比较虚拟 MyDerived vtable (在库中实例化)和 MyDerived vtable >作为参数传递的对象引用(在可执行文件中实例化。)有些东西应该立即引起注意。

其他提示

由于lib只是一个容器,如果你在两种情况下链接相同的.obj文件,那么Brian说他们不应该(不能?)是一个区别。

要注意的一件事是,如果您更改了MyBase的定义,您显然需要使用它重新编译库和代码。例如,如果您在值方法之前向MyBase添加了一个新的虚拟方法,那么这会弄乱库,因为v-table的值偏移量会有所不同。

应该没有区别。只需确保您所包含的.h文件对应于您正在链接的.lib。我怀疑你可能正在链接到一个旧的.lib文件。

如果您使用的是visual studio,而不是显式指定.lib文件,只需右键单击该项目并将依赖项设置为.lib项目即可。这样你就可以确定它使用正确的.lib文件。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top