| |
| Posted by Steven Schveighoffer in reply to frame | PermalinkReply |
|
Steven Schveighoffer
| On 5/1/21 12:55 AM, frame wrote:
> I always thought as long as an object implements an interface, it should be able to cast it from a void* if it really points to a supporting object.
>
> I have the similar structure:
>
>
> ```d
> interface AI {
> string doSomething();
> }
>
> template S() {
> void foo() {
>
> }
> }
>
> abstract class A : AI {
> string doSomething() {
> return "Hello, World";
> }
> }
>
> class B : A {
> mixin S;
>
> void other() {
>
> }
> }
>
> auto b = new B;
> auto p = cast(void*) b;
> auto c = cast(AI) p;
>
> c.doSomething();
> ```
>
> But in my code with the real object, this generates a RangeError, AcccesError, memory garbage:
> ```d
> auto b = new B;
> auto p = cast(void*) b;
> auto c = cast(AI) p; // AI with corrupt data
>
> c.doSomething(); // error
> ```
>
> But this works:
> ```d
> auto b = new B;
> auto p = cast(void*) b;
> auto c = cast(A) p; // A with correct data
>
> c.doSomething(); // no error
> ```
>
> If the runtime could not successfully cast it to AI, it should return null. Am I wrong here?
An interface cast involves a thunk (constant pointer adjustment) to get to the interface/object. The reason is because a class with interfaces stores interface vtable pointers inside the object, and your interface reference points at that. You can see when you cast between Object (concrete) type and Interface type, the pointer value changes.
So this will not work. It *does* work for base classes, because the class vtable pointer is stored at same point, and casting around class references does not involve a thunk.
If you want this to work, you have to know whether the void* pointer is pointing at an object, or an interface. If you know it's pointing at an object, you can get to the interface via:
auto c = cast(AI)cast(Object)p;
Which will perform the appropriate thunks.
If you know it's a pointer to the AI interface directly, you can just cast it directly.
-Steve
|