On Monday, 24 May 2021 at 20:31:18 UTC, sighoya wrote:
> On Monday, 24 May 2021 at 17:39:38 UTC, Gavin Ray wrote:
> Hence why I was asking how to make D structs/classes that have compatible or identical vtables to multiply inherited objects to pass as arguments to extern (C++)
functions.
I think classes annotated with extern is your only high level guaranteed == type safe option to be compatible to other c++ classes.
But you seek for the general multiple inheritance case which seems not to be supported with extern
, sadly.
So you stick with manual solutions like template metaprogramming or/and raw pointer fiddling.
Anyway, both solutions would require an unsafe cast in the end, so you are on your own.
The below seems to work at least, which is encouraging:
#include <cstdio>
#define DLL_EXPORT __declspec(dllexport)
class Base1 {
public:
virtual void overrideMe1() = 0;
const int getSomething() { return 42; }
};
class Base2 {
public:
virtual void overrideMe2() = 0;
const int getOtherThing() { return 99; }
};
class Derived : public Base1, public Base2 {
public:
int someInt;
Derived(int someIntVal) { this->someInt = someIntVal; }
virtual void overrideMe1() override;
virtual void overrideMe2() override;
};
DLL_EXPORT void takesADerived(Derived* derived)
{
printf("[C++] Calling Derived::overrideMe1() \n");
derived->overrideMe1();
printf("[C++] Calling Derived::overrideMe2() \n");
derived->overrideMe2();
printf("[C++] Calling Derived::getSomething() = %d \n",
derived->getSomething());
printf("[C++] Calling Derived::getOtherThing() = %d \n",
derived->getOtherThing());
printf("[C++] Derived::someInt = %d \n", derived->someInt);
}
import core.stdc.stdio : printf;
extern (C++)
{
void takesADerived(Derived derived);
interface Base1 { void overrideMe1(); }
interface Base2 { void overrideMe2(); }
class Derived : Base1, Base2
{
int someInt;
this(int someIntVal) { this.someInt = someIntVal; }
void overrideMe1() { printf("[D] Dlang Derived overrideMe1 called \n"); }
void overrideMe2() { printf("[D] Dlang Derived overrideMe1 called \n"); }
}
}
void main()
{
auto dlangDerived = new Derived(123);
printf("[D] Calling C++ takesADerived() with D Derived* \n");
takesADerived(dlangDerived);
}
Unfortunately, it does not work if I try to add final int getSomething()
or the other one to the D interfaces, it throws a symbol error because the mangled names are slightly different:
unresolved external symbol "public: int __cdecl Base1::getSomething(void)"
(?getSomething@Base1@@QEAAHXZ)
0000000000000000 T ?getSomething@Base1@@QEAA?BHXZ # < "nm" output
If I use nm
and list the symbols, and then try to manually use the mangling scheme, it almost works but because the return types differ it won't compile =/
extern class Derived : Base1, Base2
{
int someInt;
pragma(mangle, "?getOtherThing@Base2@@QEAA?BHXZ")
int getOtherThing();
}
main.d(29): Error: Function type does not match previously declared function with the same mangled name: `?getOtherThing@Base2@@QEAA?BHXZ`
main.d(29): Previous IR type: i32 (%main.Base2*)
main.d(29): New IR type: i32 (%main.Derived*)