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

evilrat evilrat666 at gmail.com
Tue May 25 06:02:55 UTC 2021


On Tuesday, 25 May 2021 at 02:47:19 UTC, Gavin Ray wrote:
>
> 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 at Base1@@QEAAHXZ)
> 0000000000000000 T ?getSomething at 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 at Base2@@QEAA?BHXZ")
>   int getOtherThing();
> }
> ```
>
> ```sh
> main.d(29): Error: Function type does not match previously 
> declared function with the same mangled name: 
> `?getOtherThing at Base2@@QEAA?BHXZ`
> main.d(29):        Previous IR type: i32 (%main.Base2*)
> main.d(29):        New IR type:      i32 (%main.Derived*)
> ```

That's just LDC thing, should work with DMD.
Are you sure `getOtherThing` marked final? Because in your C++ 
class it is not virtual and in your example it is not final as 
well.
In C++ having multiple bases with final method means that both 
Base1 and Base2 have their own instances of that method.

Anyway in order to call it you'll have to cast manually to target 
base.
i.e. if you want to call `Base1::getOtherThing` and you have 
`Derived` you'll have to cast to `Base1`.


```d
Derived d;
// d.getOtherThing(); // likely won't link
(cast(Base1)d) .getOtherThing(); // will call Base1 variant
(cast(Base2)d) .getOtherThing(); // will call Base2 variant
```

It is also possible that you'll have to put them in using mixin 
template so it will create scope for them that doesn't collide 
with each other, though I think it's more of a hack than a 
feature.

Something like
```d
class Derived
{
    mixin base1; // has final getOtherThing
    mixin base2; // has final getOtherThing
}
```

then you can call it almost like in C++
```d
d.base1.getOtherThing();
d.base2.getOtherThing();
```

Anyway all this stuff requires thorough research & testing as 
such ABI tinkering is very easy to mess up and very hard to 
debug, for example if you mess up the order(functions layout) it 
can land on another final method call that seemingly work but in 
debugger you'll see that you can't hit breakpoint in that method.
Happy debugging time!



More information about the Digitalmars-d-learn mailing list