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:
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?
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?
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@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>