extern(C++) multiple inheritence

Manu via Digitalmars-d digitalmars-d at puremagic.com
Mon Jan 18 21:10:19 PST 2016


I'm repeating this here from the depths of my prior whinge thread,
since this is kind of a new topic.

D's multiple inheritance solution is single-inheritance + interfaces.
Rightly so, it's a great solution, and this matches what all the C++
programmers I've ever worked with do anyway. Trouble is, it doesn't
seem to work with extern(C++) at the moment.

Note: this is my current hard-blocker. I can't progress without this.

Situation:

-------------------
In C++:

class Base
{
  virtual ~Base() {}
  size_t x;
};

class Interface
{
  virtual void A() = 0;
  virtual void B() = 0;
  virtual void C() = 0;
  virtual void Method() = 0;
};

class Derived : public Base, public Interface
{
  size_t y;
};

-------------------
D:

extern(C++) class Base
{
  ~this() {}
  size_t x;
}

extern(C++) interface Interface
{
  void A();
  void B();
  void C();
  void Method();
}

extern(C++) class Derived : Base, Interface
{
  size_t y;
}

-------------------

This code should work.


In C++, Derived is laid out:
{
  void *__Base_vtable;
  size_t x;
  void *__Interface_vtable;
  size_t y;
}

This is as I expect.

In D, according to the debuginfo output by DMD, Derived is reported as:
{
  void *__Base_vtable;
  size_t x;
  size_t y;
}

* The actual binary may not match the debuginfo; I didn't check, but
there is some evidence for this.

Surprisingly, this compiles, but calling Method generates wrong code:

00007FF72DB7381B  mov         rbx,qword ptr [this]
00007FF72DB7381F  mov         rcx,qword ptr [rbx+10h]  // rcx is now
__Interface_vtable!
00007FF72DB73823  mov         rcx,qword ptr [rcx]
00007FF72DB73826  sub         rsp,20h
00007FF72DB7382A  mov         rax,qword ptr [rcx]
00007FF72DB7382D  call        qword ptr [rax+18h]  // 18h is the
offset of Method, rax is wrong. [[rbx+10h]+18h] is the correct call.

We load rbx = [this], then we load rcx = [rbx+10h]. This looks good,
[rbx+10h] is the correct offset of __Interface_vtable in C++, even
though the debuginfo claims that's the offset of 'y'.
Then it gets weird; rcx = [rcx], this is effectively getting the first
function pointer in the vtable; A().
Then further compounding with rax = [rcx], loading the first 8 bytes
of program code from the function A()!
Finally it calls [rax+18h]. If rax were still __Interface_vtable, 18h
is the correct offset of the function I'm calling (Method), and it was
correct after the second opcode, but those 2 weird dereferences broke
it.

Hoping this can be supported, I can't move forward without this.


More information about the Digitalmars-d mailing list