我有这样的公共接口层次结构:
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获取它。
除了回滚到普通继承之外,还有其他解决方案吗?
答案 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)
可能不会回答你的问题...... 但强烈建议不要像你那样使用多重继承(称为“可怕的钻石”)。