Are interface methods always virtual?
Metody wirtualne interfejsy są ani ani nie wirtualnym. Ta koncepcja nie dotyczy metod interfejsów.
Z drugiej strony metody klas mogą być wirtualne lub nie-wirtualne. Rozróżnienie określa sposób wiązania wywołań metod. Metody wirtualne są wiązane w czasie wykonywania, biorąc pod uwagę typ środowiska wykonawczego obiektu. Metody nie-wirtualne są powiązane podczas kompilacji, używając typu czasu kompilacji odwołania do obiektu.
Błąd kompilatora mówi po prostu, że override
ma znaczenie tylko dla metod wirtualnych. Twój kod próbuje użyć override
dla metody, która nie jest wirtualna. Rozważmy ten program, który w ogóle nie zawiera żadnych interfejsów:
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.
Ten program nie może skompilować się z dokładnie tym samym błędem, co program. Błąd nie ma związku z interfejsami. Deklaracja, że DoSomething
będzie wirtualna, gdy zostanie wprowadzona w T1
, rozwiąże problem.
Will the redeclaration of the base method in TOmniParallelSimpleLoop
from non-virtual to virtual change the base type?
Tak, będzie. Zmienia tę metodę z nie wirtualnej na wirtualną. Oznacza to, że wysyłanie metod odbywa się w różny sposób, jak opisano powyżej. Oznacza to, że VMT typu zmienia się, aby dostosować się do nowej wirtualnej metody.
Or was the method already virtual to begin with (due to it being an implementation of an interface method)?
Fakt, że metoda służy do implementacji części interfejsu, nie zmienia sposobu, w jaki kompilator ją traktuje. Metoda nie-wirtualna jest zaimplementowana w taki sam sposób, niezależnie od tego, czy implementuje ona metodę interfejsu, czy nie. Podobnie w przypadku metody wirtualnej. Generowanie VMT w celu implementacji interfejsu stanowi odrębny problem.
Opracowanie na tej podstawie, każda metoda ma adres. Podczas wywoływania metody innej niż wirtualna kompilator dokładnie wie, którą metodę wywołać. Więc może emitować kod, aby wywołać tę znaną metodę bezpośrednio. W przypadku metody wirtualnej kompilator nie wie, która metoda zostanie wywołana. Jest to określone przez typ środowiska wykonawczego. Tak więc kompilator emituje kod, aby odczytać znany wpis w VMT obiektu, a następnie wywołać tę metodę.
Teraz, jak jestem pewien, wiesz, interfejsy są również realizowane za pomocą VMT. Nie oznacza to jednak, że metody wdrażania automatycznie stają się wirtualne. Interfejs to po prostu VMT. Metody przywoływane przez interfejs VMT mogą być wirtualne lub nie-wirtualne, gdy są uważane za metody klasy.
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;
Fakt, że metoda może zostać wywołana za pomocą VMT, nie oznacza, że należy ją wywoływać w ten sposób.
Prawdziwym pytaniem, które powinieneś zadać, jest to, jak Delphi kompiluje T1. Jeśli T1.DoSomething jest statyczny. Wszystkie książki COM stwierdzają, że COM = VMT. W jaki sposób T1.DoSomething dostaje się do VMT? Myślę, że to jest miejsce, w którym dzieje się twoje zamieszanie. Ponieważ nie jest to klasa VMT dla wirtualnych wywołań metod, ale VMT, która mapuje metody, czy ich statyczny, wirtualny lub dynamiczny, więc interfejs wie, do jakiej metody wywołać ... Oto świetna artykulacja, która pokazuje, jak zaimplementować interfejs bez obiektu . https://sergworks.wordpress.com/2012/04/01/interfaces-without-objects/ –