【问题标题】:(Delphi) Call Child's procedure from Parent(Delphi) 从 Parent 调用 Child 的过程
【发布时间】:2014-05-02 06:19:42
【问题描述】:

父过程如何调用被自身覆盖的子过程?

type
  TBase = class(TForm)
  procedure BtnRefreshClick(Sender: TObject);
  protected
    text: string;
end;

procedure TBase.BtnRefreshClick(Sender: TObject);
begin
  showmessage(text);
end;

type
  TParent = class(TBase)
  protected
    procedure doThis;
  end;

procedure TParent.doThis;
begin
  // blah blah do something
  BtnRefreshClick(nil);
end;

type
  TChild = class(TParent)
  procedure BtnRefreshClick(Sender: TObject);
  protected
    procedure clicky; override;
  end;

procedure TChild.BtnRefreshClick(Sender: TObject);
begin
  text := 'Hello, World!';
  inherited;
end;

实际调用过程会有点像:

child := TChild.Create;
child.doThis;

如果我尝试执行child.BtnRefreshClick;,那么它将产生一个Hello, World! 的对话框,因为调用了TChild.BtnRefreshClick 并设置了text 变量。

但是当我调用child.doThis 时,它只会显示一个空对话框,因为child.doThis 调用parent.doThis 然后??.BtnRefreshClick。如何让parent.doThis 拨打child.BtnRefreshClick?不可能吗?

提前致谢,
尤汉·W。

【问题讨论】:

  • 您所说的与您的代码不符。如果实例是 TChild,则 doThis 将调用 TChild.Clicky,因为此方法是虚拟的并且被覆盖。此外,当您谈论两种不同的 doThis 方法时,我只看到一种。
  • @StefanGlienke:不是真的。 clicky 实际上是 TParent 父类上的 TdxBarButton.onClick 事件。 doThis 是我在 TParent 类中声明并从 TChild 调用的自定义受保护虚拟过程。
  • 您可以通过简单的网络搜索来回答这个问题。请不要认为 SO 取代了网络搜索。但它是完全没有意义的 postink 假代码。不要那样做。
  • BtnRefreshClick 显然是 btnRefresh 的事件处理程序,并且您正在使用表单继承。可以将 BtnRefreshClick 方法标记为虚拟(未经测试),或者您可以调用 btnRefresh.Click 来触发正确的事件处理程序。
  • @StefanGlienke :是的,它已经解决了。就像你说的那样打电话给btnRefresh.click而不是btnRefreshClick(nil)。多谢。 @DavidHeffernan:那么很好,我将离开就 SO 提出问题,因为我的问题不足以在 SO 上显示。

标签: delphi overriding


【解决方案1】:

父类调用基类的方法,因为这是存在于父类范围内的唯一方法。当编译器编译TParent代码时,它将名称BtnRefreshClick绑定到基类中的方法,而不是子类中的方法,因为子类不是父类的祖先。

一般来说,对于一个父对象调用子类的方法,该方法应该在父对象(或更高级别)中声明并且是虚拟的。如果您将TBase 更改为虚拟BtnRefreshClick,并将TChild 更改为覆盖相同的方法,那么当TParent.doThis 调用它时,调用将被调度到TChild方法。

type
  TBase = class(TForm)
    procedure BtnRefreshClick(Sender: TObject); virtual;
  end;

  TChild = class(TParent)
    procedure BtnRefreshClick(Sender: TObject); override;
  end;

在通过 DFM 设置通过名称分配方法属性的表单的特殊情况下,另一种解决方案是 Saintfalcon's answer 演示的,即调用关联按钮的 Click 方法。当TChild 表单上的按钮被实例化时,VCL 读取DFM 资源并找到与按钮的OnClick 事件关联的字符串“BtnRefreshClick”。它使用表单的MethodAddress 函数查找具有该名称的方法的地址,并找到属于TChild 的方法。它将该值分配给OnClick 属性。 Click 方法读取该属性并调用那里的任何方法。

我之前写过关于 the differences between calling an event-handler method directly, calling the event-handler property, and calling the event trigger 的文章,但当时我还没有考虑这里说明的方面,即处理程序在后代类中被隐藏或覆盖。

【讨论】:

  • 很高兴您从其他 cmets 中得出了这个答案。谢谢!
  • 感谢您更详尽的解释。
【解决方案2】:

正如@StefanGlienke 所说,使用btnRefresh.click

procedure TParent.doThis;
begin
  // blah blah do something
  // BtnRefreshClick(nil); // this will call TBase.BtnRefreshClick
  btnRefresh.Click; // use this instead to call TChild.BtnRefreshClick
end;

谢谢

【讨论】:

  • +1:很好,您检查了解决方案是否有效。请注意,当您有一个不同的OnABC 事件时,组件没有您可以调用的ABC 方法,那么@StefanGlienke 建议将MyControlABC 方法(在您的情况下为BtnRefreshClick)设置为virtual 一个和覆盖后代类中的每个MyControlABC 也可以。男孩,我希望我们有一个像约翰斯基特这样的人。他的代表和举止有助于积极鼓励人们写出更好的问题和答案。感谢您的坚持!
  • @Jeroen 据我了解,该评论是针对我的。我认为告诉提问者他们的问题没有问题时没有帮助。即使现在它也有损坏和伪造的代码。当他们问 SSCCE 是什么时,我认为应该鼓励他们进行网络搜索。我从以前的 cmets 知道您更喜欢为他们进行网络搜索并提供链接并总结这些链接。我认为忽略不好的问题并让提问者继续认为这样问没问题是没有帮助的
  • @Jeroen 如果有同事带着假代码来找我,他们会被送走并被告知返回真实代码。他们会这样做。而且他们不会犯两次错误。
  • @David 这不是针对你的。它是针对整个 Delphi 社区的,目的是让更多的人在这里以积极的方式指导人们,以更好地编写问题和答案。我已经指导过很多客户编写更好的代码。不是针对他们的错误,而是从他们做得好的事情开始,然后从那里改进。这真的很有效,现在他们中的一些人也帮助指导其他人。 Saintfalcon 做得很好,首先开始写一个问题。
  • @Jeroen 我同意其中的大部分内容,但我认为这种方法可能太过分了。如果人们不被告知他们的问题出了什么问题,那么有什么动力可以改进?同样,如果人们编辑问题以改进它们。这里的提问者实际上确实很努力,但原始问题中的代码与问题相去甚远,很难补救。带走的消息是写一个 SSCCE,并在发布前立即对其进行测试。待定。
猜你喜欢
  • 2016-03-22
  • 1970-01-01
  • 1970-01-01
  • 2018-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多