5

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

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

4 回答 4

8

我不认为你可以指望任何编译器兼容的内置类。Borland 是否声称他们可以加载 MSVC 构建的类并与之互操作。如果是这样,看起来他们有一个错误。据我所知,C++ 规范中没有关于 VTable 的确切结构的任何内容,因此预计它不会跨编译器工作。

于 2009-06-24T14:25:22.147 回答
7

与 C 不同的是,C++ 没有交叉编译器 ABI——编译器可以自由地以任何他们想要的方式实现虚拟继承(甚至普通继承)。

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

注意:支持构建 COM 对象(或可以选择这样做)的编译器在其对象布局中受到更多限制。(我知道最新版本的 MSVC++ 产生兼容 COM 的对象,至少在大多数情况下——但不确定是否涵盖了虚拟继承。)

于 2009-06-24T14:29:00.250 回答
0

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

如果您使用多重继承,那么类型信息可能很重要。考虑:

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

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

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

现在:

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

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

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

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

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

于 2009-06-24T18:21:26.820 回答
-2

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

于 2009-06-24T14:25:05.313 回答