gpt4 book ai didi

class - 接口(interface)方法总是虚拟的吗?

转载 作者:行者123 更新时间:2023-12-03 14:46:44 27 4
gpt4 key购买 nike

编译以下代码时出现错误:

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

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

如果我将祖先方法设置为虚拟,那么错误就会消失。

但是祖先方法是在以下位置声明的:

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

TOmniParallelSimpleLoop 中的基方法从非虚拟重新声明为虚拟是否会更改基本类型,或者该方法一开始就已经是虚拟的(因为它是接口(interface)方法的实现) )?

换句话说:当接口(interface)方法从非虚拟变为虚拟时,编译器会输出不同的代码吗?

重现错误的基本 MSVC

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.

最佳答案

Are interface methods always virtual?

接口(interface)的方法既不是虚拟的也不是非虚拟的。这个概念不适用于接口(interface)的方法。

另一方面,类的方法可以是虚拟的或非虚拟的。这种区别决定了方法调用的绑定(bind)方式。虚拟方法在运行时绑定(bind),考虑到对象的运行时类型。非虚方法在编译时绑定(bind),使用对象引用的编译时类型。

编译器错误只是告诉您override仅对虚拟方法有意义。您的代码正在尝试对非虚拟方法使用override。考虑这个程序,它根本不包含任何接口(interface):

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.

该程序无法编译,并出现与您的程序完全相同的错误。该错误与接口(interface)无关。在 T1 中引入 DoSomething 时将其声明为虚拟将解决该错误。

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

是的,会的。它将该方法从非虚拟更改为虚拟。这意味着方法分派(dispatch)的执行方式不同,如上所述。这意味着该类型的 VMT 会发生变化以适应新的虚拟方法。

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

方法用于实现接口(interface)的一部分这一事实不会改变编译器处理它的方式。非虚方法无论是否实现接口(interface)方法,其实现方式都是相同的。对于虚拟方法也是如此。为实现该接口(interface)而生成的 VMT 是一个明显的问题。

详细说明一下,每个方法都有一个地址。当调用非虚方法时,编译器准确地知道要调用哪个方法。因此它可以发出代码来直接调用该已知方法。对于虚方法,编译器不知道将调用哪个方法。这是由运行时类型决定的。因此编译器会发出代码来读取对象 VMT 中的已知条目,然后调用该方法。

现在,我相信您知道,接口(interface)也是使用 VMT 实现的。但这并不意味着实现方法会自动升级为虚拟的。接口(interface)就是一个 VMT。当被视为类的方法时,接口(interface) VMT 引用的方法可以是虚拟的或非虚拟的。

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;

因此,可以通过 VMT 调用方法这一事实并不意味着必须以这种方式调用它。

关于class - 接口(interface)方法总是虚拟的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36137977/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com