不同的编译器的C ++虚拟继承实现不兼容吗?

时间:2009-06-24 14:17:06

标签: c++ visual-c++ c++builder virtual-inheritance

我有这样的公共接口层次结构:

struct ISwitchable {
    /* Obtain pointer to another implemented interface of the same instance. */
    virtual int switch(unsigned int interfaceId, void** pInstance) = 0;
};
struct IFoo : public ISwitchable { /* Methods */ };
struct IBar : public ISwitchable { /* Methods */ };
struct IFooBar : public IFoo, public IBar { /* Methods */ };

实现IFooBar的类与工厂函数一起放入dll。客户端代码加载dll,使用工厂函数创建类实例并根据接口使用它们(它们作为头文件提供)。

Scheme可以使用由MSVC制作的dll和Borland C ++ Builder 6制作的客户端代码。

我将虚拟继承引入层次结构:

struct IFoo : public virtual ISwitchable { /* Methods */ };
struct IBar : public virtual ISwitchable { /* Methods */ };

当处于相同的情况(由MSVC的dll,客户端由Builder构建)客户端代码请求类的实例时,他会用凌乱的vtable获取它。

除了回滚到普通继承之外,还有其他解决方案吗?

4 个答案:

答案 0 :(得分:8)

我认为你不能指望任何构建的类在编译器之间兼容。 Borland声称他们可以加载和与MSVC构建的类进行互操作。如果是这样,看起来他们有一个bug。据我所知,关于VTable的确切结构的任何内容都不在C ++的规范中,因此预计不会在编译器之间起作用。

答案 1 :(得分:7)

与C不同,C ++没有交叉编译器ABI - 编译器可以随心所欲地实现虚拟继承(甚至普通继承)。

结果是:不能保证在编译器之间调用C ++函数。我知道它很难看,但是如果你希望你的DLL与多个编译器愉快地交互,你可能更好地提供一组普通的extern "C"函数和手动构建的函数指针表。

注意:支持构建COM对象(或有选项)的编译器在其对象布局中受到更多限制。 (我知道最近版本的MSVC ++生成符合COM的对象,至少在大多数情况下 - 不确定是否覆盖了虚拟继承。)

答案 2 :(得分:0)

我对void**论证持怀疑态度。使用void指针会丢失类型信息。

如果您正在使用多重继承,那么输入信息可能很重要。考虑:

class Foo { ... };
class Bar { ... };

class Both: public Foo, public Bar { ... };

让我们假设在两个实例的内部布局是一个Foo实例,后跟一个Bar实例。我可以将Both *传递给期望Foo *的方法没有问题。我也可以将Both *传递给期望Bar *的方法,前提是我将指针调整为指向嵌入的Bar。我可以做到这一点,因为我知道我正在使用Both。

现在:

Foo *foo = new Both(...);
Bar *bar = new Both(...);

void *p = foo;
void *q = bar;

Both *both = (which) ? (Both*)p : (Both*)q;

那么:当我分配给“both”时,我如何知道如何调整p或q?我不能,因为通过void指针丢失了类型信息。

此问题的变体可能与您遇到的问题有关。

答案 3 :(得分:-2)

可能不会回答你的问题...... 但强烈建议不要像你那样使用多重继承(称为“可怕的钻石”)。