Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are interface methods always virtual?

When compiling the following code I get an error:

TOmniParallelSimplePooledLoop = class(TOmniParallelSimpleLoop)
  procedure Execute(loopBody: TOmniIteratorSimpleSimpleDelegate); overload; override;

[dcc64 Error] OtlParallel.pas(846): E2170 Cannot override a non-virtual method

If I make the ancestor method virtual then the error goes away.

However the ancestor method is declared in:

IOmniParallelSimpleLoop
  ...
  procedure Execute(loopBody: TOmniIteratorSimpleSimpleDelegate); overload;

Will the redeclaration of the base method in TOmniParallelSimpleLoop from non-virtual to virtual change the base type, or was the method already virtual to begin with (due to it being an implementation of an interface method)?

In other words: will the compiler output different code when an interfaced method is changed from non-virtual to virtual?

Basic MSVC to recreate the error

program Project70;
{$APPTYPE CONSOLE}
uses
  System.SysUtils;

type
  I1 = interface
    procedure DoSomething;
  end;

  T1 = class(TInterfacedObject, I1)
    procedure DoSomething;
  end;

  T2 = class(T1)
    procedure DoSomething; override;
  end;

procedure T1.DoSomething;
begin
  WriteLn('parent');
end;

procedure T2.DoSomething;
begin
  Writeln('Child');
end;

begin
end.
like image 378
Johan Avatar asked Mar 21 '16 17:03

Johan


People also ask

Should all methods be virtual?

No, you should not mark all methods as virtual. You should consider how your class could be inherited. If the class should not be inherited, then mark it sealed and obviously the members should not be virtual. If your class is likely to be inherited, you really should maximize the ability to override the behavior.

Can a method derived from interface marked as virtual?

An implementing class is free to mark any or all of the methods that implement the interface as virtual. Derived classes can override or provide new implementations. For example, a Document class might implement the IStorable interface and mark the Read( ) and Write( ) methods as virtual .

Are all methods in C# virtual?

The C# programming language provides support for both virtual and abstract methods, each of which has distinct advantages. You use virtual methods to implement late binding, whereas abstract methods enable you to force the subclasses of the type to have the method explicitly overridden.

Can we create virtual method in interface in C#?

Yes, interface implementation methods are virtual as far as the runtime is concerned. It is an implementation detail, it makes interfaces work. Virtual methods get slots in the class' v-table, each slot has a pointer to one of the virtual methods.


2 Answers

Are interface methods always virtual?

Methods of interfaces are neither virtual nor non-virtual. That concept does not apply to methods of interfaces.

On the other hand, methods of classes can be virtual or non-virtual. The distinction determines how the method calls are bound. Virtual methods are bound at runtime, taking account of the runtime type of the object. And non-virtual methods are bound at compile time, using the compile time type of the object reference.

The compiler error is simply telling you that override is only meaningful for virtual methods. Your code is attempting to use override on a method that is not virtual. Consider this program, which does not contain any interfaces at all:

type
  T1 = class
    procedure DoSomething;
  end;

  T2 = class(T1)
    procedure DoSomething; override;
  end;

procedure T1.DoSomething;
begin
end;

procedure T2.DoSomething;
begin
end;

begin
end.

This program fails to compile with exactly the same error as your program. The error is unrelated to interfaces. Declaring DoSomething to be virtual when it is introduced in T1 will resolve the error.

Will the redeclaration of the base method in TOmniParallelSimpleLoop from non-virtual to virtual change the base type?

Yes it will. It changes that method from non-virtual to virtual. That means that method dispatch is performed differently, as described above. It means that the type's VMT changes to accommodate the new virtual method.

Or was the method already virtual to begin with (due to it being an implementation of an interface method)?

The fact that a method is used to implement part of an interface does not change how the compiler treats it. A non-virtual method is implemented in the same way whether it implements an interface method or not. Likewise for a virtual method. The VMT generated to implement the interface is a distinct concern.

Elaborating on that, every method has an address. When calling a non-virtual method, the compiler knows precisely which method to call. So it can emit code to call that known method directly. For a virtual method, the compiler does not know which method will be called. That is determined by the runtime type. So the compiler emits code to read the known entry in the object's VMT, and then call that method.

Now, as I'm sure you know, interfaces are also implemented using VMTs. But that does not mean that the implementing methods get automatically promoted to being virtual. An interface is simply a VMT. The methods referred to by the interface VMT can be virtual or non-virtual, when thought of as methods of the class.

type
  ISomeInterface = interface
    procedure Foo;
  end;

  TSomeObject = class(TInterfacedObject, ISomeInterface)
    procedure Foo;
  end;

....

var
  Intf: ISomeInterface;
  Obj: TSomeObject;
....
Intf := TSomeObject.Create;
Obj := Intf as TSomeObject;

// non-virtual method, direct dispatch at compile time
Obj.SomeMethod; 

// interface method, dispatched via interface VMT
Intf.SomeMethod;

So, the fact that a method can be invoked via a VMT does not imply that it must be invoked that way.

like image 154
David Heffernan Avatar answered Sep 19 '22 17:09

David Heffernan


I think the answer to this is contained in a single sentence of Danny Thorpe's "Delphi Component Design", ISBN 0-201-46136-6, I mentioned in a comment to @DavidH's answer:

"A VMT is precisely an array of function pointers", in the section "Importing Objects from DLLs - The Hard Way", p.89.

The following section, "Importing Objects from DLLs - The Smart Way" explains how an array of function pointers to members of an abstract interface can be used to call into a DLL which implements the interface and how this (stroke of genius, not just imo) provided the basis of Delphi's COM support (once it got past support via variants of D2).

like image 42
MartynA Avatar answered Sep 20 '22 17:09

MartynA