我有一个带有静态方法的类,大致如下:
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,我明白了。
如果我创建一个包含 X.obj 文件并在 .lib 中链接的 .lib,它会中断。当我调用 getFloat() 时,它返回-1.#IND00。这是某种类型的哨兵值,应该告诉我这里出了什么问题吗?
当您在 lib 中链接而不是直接在 obj 中链接时,有什么不同吗?
我没有收到任何编译器警告或错误。
编辑:
我在 Windows XP Pro SP3 上使用 Visual Studio 2005。为了确保我没有链接旧文件,我将 value() 方法克隆到一个新的 value2() 方法中并改为调用它。行为是一样的。
编辑#2:
因此,如果我使用调试器跟踪调用,我发现它根本不会进入我的 value() 方法。相反,它进入了一种不同的(不相关的)方法。这让我觉得我的 vtable 已损坏。我认为我看到的行为一定是其他问题的副作用。
解决了!(感谢弗拉德)
事实证明我违反了单一定义规则(ODR),尽管从我发布的代码中并不明显。这是来自 Visual C++ 人员的一篇很棒的文章,它解释了这个问题以及一种追踪它的方法。/d1reportSingleClassLayout编译器标志是一个很棒的学习工具。
当我在两个不同的项目中为 MyBase 和 MyDerived 倾倒我的类布局时,我发现调用代码和库代码之间存在差异。事实证明,我的头文件中有一些#ifdef块,相应的#define语句位于主项目的预编译头文件中,但不在子项目(库)中。我有没有提到我认为预处理器宏有多邪恶?
无论如何,我只是发布这些东西,因为它可能对其他人有帮助。这个问题对我也很有帮助。