Tutorial :Are different compilers' C++ virtual inheritance implementations incompatible?



Question:

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?


Solution:1

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.


Solution:2

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.)


Solution:3

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.


Solution:4

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


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »