Delphi 析构函数:在调用 inherited 后执行代码?

8

在Delphi中,在调用继承的析构函数之后执行代码是否真的可行?

您可以在System.Classes中找到相关信息:

destructor TThread.Destroy;
begin
[...]
  inherited Destroy;
  FFatalException.Free;
end;

我认为在调用继承的Destroy方法后访问实例成员是不好的做法。


1
我认为这不太好。 - Jerry Dodge
@JerryDodge:实际上,这可能非常必要。例如,当您需要保护析构函数免受异常和/或多线程执行时。在这种情况下,您几乎总是会在继承调用之后执行代码。还可以确保成员实例的生命周期,这些实例提供了可以从继承的析构函数中调用的回调。换句话说:有很多原因可以这样做,但我确实同意这是需要非常仔细地考虑的事情。 - Marjan Venema
2
在构造函数中继承调用之前构建事物是正确的,虽然不常见但仍然有效。此外,TThread从TObject继承,因此在该继承调用中也不会发生任何事情。 - Stefan Glienke
2个回答

10

在调用继承的析构函数后执行代码是完全安全的,只要该代码不依赖于被该继承的析构函数销毁的任何内容。同样地,在调用继承的构造函数之前执行代码也是安全的,只要该代码不依赖于在该继承的构造函数中实例化的任何内容。

但是这种写法并不好,这是肯定的。有时候会有理由让您编写这种代码,但通常这些原因应该被视为设计上的问题指示。

在您给出的示例中,没有必要以这种方式编写代码。对 FFatalException.Free 的调用可以在调用继承的析构函数之前完全进行。


5

实例在内存中不是由析构函数本身删除的,而是通过调用TObject.FreeInstance方法进行删除。

由于析构函数代码的处理是后置的,所以会调用TObject.FreeInstance方法。

顺带一提:构造函数也是同样的道理。实例是通过class function TObject.NewInstance : TObject创建的,并且在调用构造函数之前(因为它是构造函数)被调用。

正因为如此,您将在整个构造函数或析构函数代码中拥有有效的实例。


即使实例已经消失,只要您不引用该实例,就可以执行代码。 - David Heffernan
@DavidHeffernan 这是所有方法都共有的,但问题是关于继承后类的一个字段,并且引用了该实例; o) - Sir Rufo
这个例子肯定是这样的。我更加通用地说,就像“在析构函数中,在调用继承后执行代码是否真的可以在Delphi中使用?” - David Heffernan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接