How does inheritance and vtables work wrt. C++ and interop with D? Fns w/ Multiple-inheritance args impossible to bind to?

Gavin Ray gavinray at site.com
Sun May 23 19:44:01 UTC 2021


So one of the problems with generating D code for bindings to C++ 
is that there's no true/direct multiple inheritance.

If anyone happens to understand well how vtables work and the way 
the compiler treats these things, is there a way to hackily make 
semantically-equivalent objects?

An example:

```cpp
class Kickable {
   void nonVirtual() { /* impl */ }
   virtual void kick();
}

class Throwable {
   virtual void throw();
}

class KickableThrowable : Kickable, Throwable {}

// KickableThrowable or KickableThrowable*, not really sure which 
is more realistic
void takesKickableThrowable(KickableThrowable* thing) {}
```

Would making a class/struct that has the methods `nonVirtual()`, 
`kick()`, and `throw()` be usable as an argument to 
`takesKickableThrowable()`, since it would contain identical 
members/layout?

```d
extern (C++)
class KickableThrowable {
    void nonVirtual();
    /* override */ void kick() {}
    /* override */ void kick() {}
}

extern (C++)
void takesKickableThrowable(KickableThrowable thing);

takesKickableThrowable(new KickableThrowable());
```

adr had shown me a way to mimic multiple inheritance using 
interfaces and mixin templates, would this be a viable approach?

- See: https://run.dlang.io/is/3rJyMt

```d
interface Abstract1 {
     /* virtual */ void overrideMe1();

     void sayHello();
     mixin template Abstract1Impl() {
         void sayHello() { import std.stdio; writeln("Hello"); }
     }
}

interface Abstract2 {
     /* virtual */ void overrideMe2();

     void sayGoodbye();
     mixin template Abstract2Impl() {
         void sayGoodbye() { import std.stdio; writeln("Goodbye"); 
}
     }
}

class MyClass : Abstract1, Abstract2 {
   mixin Abstract1Impl;
   mixin Abstract2Impl;
   override void overrideMe1() { writeln("overrode 1"); }
   override void overrideMe2() { writeln("overrode 2"); }
}
```

---

Also, what is the best way to debug and learn about vtables and 
their impact on interopability in D?

Visual Studio has the "Struct Layout" extension (pictured below), 
and `clang` and `cl.exe` have options to dump vtable/record 
layouts:

```
$ cl.exe test.cpp /d1reportSingleClassLayoutMEOW

class BatMEOW   size(40):
         +---
  0      | +--- (base class Mammal)
  0      | &Mammal::Breathe

BatMEOW::$vftable at WingedAnimal@:
         | -16
  0      | &WingedAnimal::Flap

<SNIPPED>

BatMEOW::{dtor} this adjustor: 32
BatMEOW::__delDtor this adjustor: 32
BatMEOW::__vecDelDtor this adjustor: 32
vbi:       class  offset o.vbptr  o.vbte fVtorDisp
           Animal      32       8       4 0
```

```
$ clang -cc1 -fdump-vtable-layouts -emit-llvm  test.cpp

VFTable for 'Animal' (3 entries).
    0 | Animal RTTI
    1 | Animal::~Animal() [scalar deleting]
    2 | void Animal::Eat()

<SNIPPED>
```

```
$ clang -cc1 -fdump-record-layouts -emit-llvm  test.cpp

*** Dumping AST Record Layout
          0 | struct Animal
          0 |   (Animal vftable pointer)
            | [sizeof=8, align=8,
            |  nvsize=8, nvalign=8]

*** Dumping AST Record Layout
          0 | struct Mammal
          0 |   (Mammal vftable pointer)
          8 |   (Mammal vbtable pointer)
         16 |   struct Animal (virtual base)
         16 |     (Animal vftable pointer)
            | [sizeof=24, align=8,
            |  nvsize=16, nvalign=8]
<SNIPPED>
```

![vtable inspector cpp](https://i.imgur.com/Xqw6jKG.gif)





More information about the Digitalmars-d-learn mailing list