gpt4 book ai didi

delphi - 调用子类非虚方法或设置子类属性

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

我有一个基类TThread,它具有TThreadSockTThreadPool等子类,它们覆盖.Terminate() 方法。这些子项的子项(例如 TThreadSockDownloadTThreadPoolCollect)继承这些 .Terminate() 方法(或者甚至可能覆盖它们):

type
TThreadSock= class( TThread )
procedure Terminate; // Hides TThread.Terminate
end;
TThreadSockDownload= class( TThreadSock );
TThreadSockUpload= class( TThreadSock )
procedure Terminate; // Hides TThreadSock.Terminate
end;

TThreadPool= class( TThread )
procedure Terminate; // Hides TThread.Terminate
end;
TThreadPoolCollect= class( TThreadPool );

我的问题是:我有一个可以包含所有内容的列表,因此最常见的分母是TThread。我需要从该基类调用最“幼稚”的 .Terminate() 方法。目前我的做法是这样的:

var
oThread: TThread;
begin
oThread:= GetNextThread();

if oThread is TThreadSockDownload then TThreadSockDownload(oThread).Terminate() else
if oThread is TThreadSockUpload then TThreadSockUpload(oThread).Terminate() else
if oThread is TThreadPoolCollect then TThreadPoolCollect(oThread).Terminate() else ...

...你就会知道这会导致什么结果。没什么可说的,我也必须在其他地方使用这段代码。如果我调用 oThread.Terminate() ,则执行基类的代码,这不是我想要的。并且将该方法定义为虚拟也不会完全起作用,因为每个子级别都可能是“最后一个”级别。或不。

我的最终目标是尽可能地概括这一点,因此我不需要将每个类(class)都要求为候选人。也许我在这里遗漏了一些基本的东西,比如 GetRealClass( oThread ).Call( 'Terminate' );GetRealClass( oThread ).Set( 'Stop', TRUE ); 将是一个梦想。

我至少能够概括这段代码,这样我只需要编写一次吗?像 FindMethod 之类的对象,我也告诉了它的类类型?

最佳答案

处理这个问题的正确方法是使用虚方法。该机制旨在允许基于对象的运行时类型进行方法分派(dispatch)。换句话说,正是您辛苦的类型检查代码所做的。

但是您正在努力解决这样一个事实:您想要将您的方法命名为 Terminate,这是一个非虚拟的现有方法的名称。那么,如何克服这个问题。

好吧,如果您决定命名为Terminate,因为您的方法调用了TThread.Terminate,然后执行其他任务,那么框架为您提供了一种简单的方法出去。让我们看看TThread.Terminate的实现。

procedure TThread.Terminate;
begin
if FExternalThread then
raise EThread.CreateRes(@SThreadExternalTerminate);
FTerminated := True;
TerminatedSet;
end;

注意对 TermminateSet 的调用。这是一个虚拟方法,其实现如下:

procedure TThread.TerminatedSet;
begin
end;

它什么也没做。提供它是为了允许您在派生类中重写它,并在调用非虚拟方法 Terminate 时调用它。

所以你会这样做:

type
TMyDerivedThread = class(TThread)
protected
procedure TerminatedSet; override;
end;

....
procedure TMyDerivedThread.TerminatedSet;
begin
inherited;
// do your class specific tasks here
end;

然后控制线程的代码可以调用非虚拟的Terminate方法,但仍然调用这个虚拟方法。

oThread := GetNextThread;
oThread.Terminate;

现在,另一方面,您的 Terminate 方法可能不会调用 TThread.Terminate。在这种情况下,方法会有所不同。您仍然需要一个虚拟方法,但如果 TThread 类尚未包含适当的虚拟方法,则需要引入一个。这意味着派生一个新的基类以引入该虚拟方法。

type
TBaseThread = class(TThread)
public
procedure MyTerminate; virtual; abstract;
end;

我已经做了这个摘要,但你可能不想这样做。我们无法判断,因为我们不知道您的线程实现是做什么的。您可以决定此方法是否应该是抽象的。

现在您可以像其他任何方法一样重写此虚拟方法,我相信您已经理解了这一点。您需要进行的另一个更改是,在对线程实例进行操作时,您不再持有 TThread 引用,而是持有 TBaseThread 引用。

关于delphi - 调用子类非虚方法或设置子类属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35744062/

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