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

时间:2016-03-02 10:08:27

标签: delphi polymorphism

我有一个基类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(),则会执行基类的代码,这不是我想要的。将方法定义为virtual也不会完全奏效,因为每个孩子级别都可能是最后一个"一。或不。

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

我至少能够推广这段代码所以我只需要写一次吗?像对象FindMethod这样的东西我也告诉它的类类型为?

1 个答案:

答案 0 :(得分:4)

处理此问题的正确方法是使用虚拟方法。此机制旨在允许基于对象的运行时类型进行方法分派。换句话说,正是您的劳动类型检查代码确实如此。

但是你正在努力解决你想要命名方法Configuration的事实,这是一个非虚拟的现有方法的名称。那么,如何超越它。

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

TThread.Terminate

请注意对procedure TThread.Terminate; begin if FExternalThread then raise EThread.CreateRes(@SThreadExternalTerminate); FTerminated := True; TerminatedSet; end; 的通话。这是一个虚拟方法,其实现如下:

TerminatedSet

它什么都不做。它被允许您在派生类中覆盖它,并在调用非虚方法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引用。