"The last feature": overridable methods in interfaces

Steven Schveighoffer schveiguy at yahoo.com
Mon Feb 8 14:42:55 PST 2010


On Mon, 08 Feb 2010 17:19:28 -0500, Andrei Alexandrescu  
<SeeWebsiteForEmail at erdani.org> wrote:

> Steven Schveighoffer wrote:
>> On Mon, 08 Feb 2010 16:09:19 -0500, Andrei Alexandrescu  
>> <SeeWebsiteForEmail at erdani.org> wrote:
>>
>>> Steven Schveighoffer wrote:
>>>> On Mon, 08 Feb 2010 15:13:33 -0500, Andrei Alexandrescu  
>>>> <SeeWebsiteForEmail at erdani.org> wrote:
>>>>
>>>>> Steven Schveighoffer wrote:
>>>>>> On Mon, 08 Feb 2010 14:36:37 -0500, Andrei Alexandrescu  
>>>>>> <SeeWebsiteForEmail at erdani.org> wrote:
>>>>>>
>>>>>>> Don wrote:
>>>>>>>>  I don't understand this. How does belowTop() know how to call  
>>>>>>>> top()?
>>>>>>>
>>>>>>> It calls top() through the normal interface mechanism. Inside  
>>>>>>> belowTop(), this has Stack!T type.
>>>>>>  Actually, I think Don has a point here.  A virtual function (even  
>>>>>> on an interface) is always called with the 'this' pointer, not the  
>>>>>> interface pointer.
>>>>>
>>>>> That is done via an adjustment of the reference. In the case of an  
>>>>> interface method, no adjustment is necessary. Inside the method,  
>>>>> "this" has the static type of the interface and the dynamic type  
>>>>> whichever class implements the interface.
>>>>   void foo(Stack!T st)
>>>> {
>>>>   auto x = st.belowTop();
>>>> }
>>>>  OK, so if st's virtual function for belowTop points to the default  
>>>> implementation, there is no adjustment.  But what if the actual  
>>>> object *did* override the default implementation?  Does it also  
>>>> receive the interface pointer as 'this'?  Where does the adjustment  
>>>> happen?  What happens if you have a reference to the actual concrete  
>>>> object type?  Do you have to thunk to the correct interface to pass  
>>>> in the expected interface pointer?  It can't be both ways.
>>>
>>> If an object overrode the default implementation, the pointer to  
>>> method belowTop will point to code that does do the adjustment.
>>  If I understand this correctly, calling such a "default  
>> implementation" function is different than calling a standard interface  
>> function.  And each entry in such an interface for a overridden method  
>> will point to a "pre function" that adjusts the 'this' reference before  
>> jumping to the real implementation.
>
> Actually that's what's happening today.

Yes, but I think it's happening at the call site and not inside the  
function itself.

I will run a test...

You are right, I was wrong.  So this is already the way it works (good to  
know!):


interface I
{
     void foo();
}

interface J
{
     void foo();
}

class C : I, J
{
     int i;
     void foo() { i = 5;}
}

produces the following asm for C.foo:

_D13testinterface1C3fooMFZv:
		push	EBP
		mov	EBP,ESP
		sub	ESP,4
		mov	dword ptr 8[EAX],5
		leave
		ret
		nop
_TMP0:
		add	EAX,0FFFFFFF4h
		jmp	near ptr _D13testinterface1C3fooMFZv
_TMP1:
		add	EAX,0FFFFFFF0h
		jmp	near ptr _D13testinterface1C3fooMFZv

where _TMP0 and _TMP1 are the little pre functions that get stored in the  
interface vtables.

I therefore don't think there are any issues, I misunderstood the way  
interface functions work.  I didn't realize the interface function called  
a little pre function.  I thought it was done at the call site before the  
call.

>
>> The vtable entries of the object itself would point to a function that  
>> does not do the adjustment, correct?
>
> Yes, but let's not forget that each object stores more than one vptrs.

Right, I just thought the different vtables contained identical references  
to the same functions.  It makes sense that is not the case.

>> I think all the information is available to make this work, the only  
>> issue I see is that a function with a default implementation  
>> artificially changes the ABI for that function.  Adding a default  
>> implementation therefore will make compiled objects incompatible, even  
>> with the same vtable layout.
>
> Not getting this, but I'll let Walter weigh in.

It's my bad, I thought normal interface calls were different than this  
method of having a little "pre" function, but it makes sense to do it that  
way.

Sorry for the noise.  I retract my objection on these grounds :)

-Steve



More information about the Digitalmars-d mailing list