最近我们在我们的遗留代码中遇到了一个有趣的效果,即目前从 VS2010 移植到 VS2015。不幸的是,我无法创建一个小例子来展示这种效果,但我会尽可能准确地描述它。
我们有 2 个 dll(我将它们称为 dll A 和 dll B)。dll A 的项目定义了接口 IFoo 和派生接口 IFxFoo
class __declspec(novtable) IFoo {
public:
virtual int GetType() = 0;
virtual ~IFoo() {}
};
class __declspec(novtable) IFxFoo : public IFoo {
public:
virtual int GetSlot() = 0;
};
在 dll B 中,使用了两个接口。
class CBImpl : public IFxFoo {
public:
...
void processFoo(IFoo* f) {
...
if (f->GetType() == IFXFOO) {
IFxFoo* fx = static_cast<IFxFoo>(f); //downcast
fill(fx);
}
}
void fill(IFxFoo* fx) {
m_slot = fx->GetSlot();
}
private:
int m_slot;
};
processFoo() 将被不同的 IFoo 实现调用。一些来自 dll A,一些来自 dll B。
现在发生的情况如下: - 如果我们在编译 dll B 时打开整个程序优化,函数 fill() 中对虚函数 GetSlot() 的调用会被 Visual C++ 反虚拟化。这导致我们的程序崩溃。如果我们要么
- 整个程序优化
- 填充优化转向
- 或者用 __declspec(dllimport) / __declspec(dllexport) 标记我们的接口
我现在的问题是:
- 我们的假设是否正确,因为优化器在 dll B 中只看到了 IFxFoo 的一个实现,并假设这是唯一的一个,因为 IFxFoo 没有被标记为来自不同的 dll?
- 在头文件中创建“接口”的最佳方法是什么?我们曾经像上面那样做,但这似乎会导致一些问题。
- 其他编译器(gcc / clang)是否表现出类似的行为?
感谢您的帮助托比亚斯