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

发布于 2024-07-25 04:14:59 字数 805 浏览 8 评论 0原文

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

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,使用工厂函数创建类实例并根据接口使用它(它们作为头文件提供)。

方案与 MSVC 制作的 dll 和 Borland C++ Builder 6 制作的客户端代码配合良好。

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

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

并且当在相同情况下(MSVC 的 dll,Builder 的客户端)客户端代码请求他获取的类的实例时凌乱的 vtable。

除了回滚到普通继承还有什么解决办法吗?

I have hierarchy of public interfaces like this:

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 */ };

Class implementing IFooBar is placed into dll along with factory function. Client code loads dll, uses factory function to create class instance and use it according interfaces (they are supplied as a header file).

Scheme works fine with dll made by MSVC and client code made by Borland C++ Builder 6.

I introduce virtual inheritance into hierarchy:

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

And when in the same situation (dll by MSVC, client by Builder) client code requests instance of class he gets it with messy vtable.

Is there any solution except of rollback to ordinary inheritance?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

沉鱼一梦 2024-08-01 04:14:59

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

I didn't think that you could count on any built classes being compatible across compilers. Does Borland claim that they can load and interoperate with classes built by MSVC. If so, looks like they have a bug. As far as I know, nothing about the exact structure of the VTable is in the spec of C++, so it isn't expected to work across compilers.

子栖 2024-08-01 04:14:59

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

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

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

Unlike for C, there is no cross-compiler ABI for C++ -- compilers are free to implement virtual inheritance (and even ordinary inheritance) any way they want.

The upshot is: calling C++ functions across compilers is not guaranteed to work. I know it's ugly, but if you want your DLL to interact happily with multiple compilers, you had probably better provide a set of plain extern "C" functions and manually-built tables of function pointers instead.

Note: Compilers that support building COM objects (or have an option to do so) are more constrained in their object layouts. (I know that recent versions of MSVC++ produce COM-compliant objects, at least in most cases -- not sure if virtual inheritance is covered though.)

删除→记忆 2024-08-01 04:14:59

我对 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 指针丢失了。

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

I'm leery of the void** argument. Using void pointers loses type information.

If you're working with multiple inheritance then type information can be important. Consider:

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

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

Let's assume that internally the layout of a Both instance is a Foo instance followed by a Bar instance. I can pass a Both* to a method expecting a Foo* without problems. I can also pass a Both* to a method expecting a Bar*, provided that I adjust the pointer to point to the embedded Bar. I can do this reliably because I know I'm working with a Both.

Now:

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

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

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

So: how do I know how to adjust either p or q when I assign to "both"? I can't because the type information is lost going through the void pointer.

A variant of this problem might be related to the problems you're having.

你穿错了嫁妆 2024-08-01 04:14:59

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

Probably will not answer your question ...
But is is strongly recommended to NOT use multiple inheritance as you do (called "dreaded diamond").

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文