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:
```cpp
#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);
}
```
```d
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:
```sh
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 =/
```d
extern class Derived : Base1, Base2
{
int someInt;
pragma(mangle, "?getOtherThing@Base2@@QEAA?BHXZ")
int getOtherThing();
}
```
```sh
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*)
```