1

我读了“Programming Perl”一书,在某些地方相当复杂。其中一个地方是第 12 章“对象”中的“实例析构函数”部分。本节说:

  1. Perl 中的对象在不再引用它们时会被销毁。
  2. DESTROY通过在其类中定义方法,有机会在对象将被回收之前捕获控制。
  3. 尽管在 Perl 中很少需要析构函数,但某些对象可能有,例如,文件句柄或数据库连接,它们在内存系统之外。所以有必要专门去参加。
  4. Perl 不做分层破坏。

然后有一段我没看懂:

这仅适用于继承的类;仅包含在当前对象中的对象(例如,较大散列中的一个值)将被自动释放和销毁。这就是为什么仅仅通过聚合(有时称为“has-a”关系)的容器通常比继承(“is-a”关系)更清晰和更清晰的原因之一。

我不明白这是什么意思。这是否意味着不简单 地包含在当前对象中的对象不会 自动释放和销毁

我确实知道DESTROY在垃圾收集上调用的 a 是最近的,也是唯一的。DESTROY当实例没有引用时,不会调用其他覆盖的方法。但是,据我了解,当将实例的引用放置在另一个对象中时,会出现相同的行为。

有人会如此愉快地解释并提供代码示例吗?


更新:

实际上我正在寻找的是对This only 适用于继承类的解释;原来是这样的话:

如果您有一个类的实例并且它有一个DESTROY方法,那么该方法将覆盖DESTROY父类的方法,但这不适用于对象,即has-a与相关对象的关系。它DESTROY不会被覆盖

对不起,不清楚的问题,它会更适合英语语言和用法。谢谢大家。

4

4 回答 4

3

规则 1:Perl 中的对象在不再引用它们时被销毁。

{
  my $object = Class->new()
}
# there are no more references to $object
# (it is out of scope and can't be accessed by any means)
# Perl is free to garbage-collect it.

规则 2:通过在其类中定义 DESTROY 方法,有机会在对象将要被回收之前捕获控制。

package Class;
sub new     { return bless({}, shift) }
sub DESTROY { print STDERR "The object is destroyed" }

####

{
  my $object = Class->new();
}
# before the object is garbage-collected, cleanup-operations should be manually performed
# like closing down connections, solving circular references
# any time, the object might print it's message.

规则 4:Perl 不做分层破坏。

package AnotherClass;
use Class;
use parent 'Class';
sub DESTROY { print STDERR "subclass reporting dead" }

现在 ifAnotherClass将被实例化,只会 调用 的方法,DESTROY不是的方法。这意味着没有分层破坏。这很明显,因为该方法会覆盖先前的条目。原来可以手动调用AnotherClassDESTROYClassDESTROYDESTROY

使用父类和子类是一种 IS-A 关系:AnotherClass是一个Class.

如果我们有 YetAnotherClass:

package YetAnotherClass;
use Class;
sub new {return bless({member => Class->new()}, shift) }

{
   my $object = YetAnotherClass->new();
}
# $object goes out of scope (zero reference count) and will be destroyed.
# Therefore, the reference count of the "member" drops to zero
# The member will therefore be destroyed and print it's message.

这是聚合的情况(Class是 的数据成员YetAnotherClass)和 HAS-A 关系。

于 2012-09-15T08:36:12.680 回答
2
  1. 在 has-a 关系中,对象通常具有对另一个对象的引用。因此,给定类Van, a 的实例Van具有轮子。当该实例被销毁时,perl(程序)将Wheel分别调用对象的析构函数,因为它们是两个不同的对象。

  2. 在 is-a 关系中,Van IS的引用与所讨论Vehicle对象的引用相同。因此,它不像某些语言那样,逐步调用DESTROY所有继承的层次结构,它只是DESTROY为每个受祝福的引用调用一次。

注意: #1 并非总是如此。例如,inside-out 对象包含对子类的引用,它们是受祝福的标量引用,其地址用作包中词法哈希的键。持久包的词法范围包含引用,而不是对象。但这只是为了使它在类清理和 is-a/has-a 关系之间没有直接关联。

仍然很清楚需要进行单独的销毁,即使 perl 不会自动获得这些 has-a 关系。

所以我认为理解这一点的关键是在has-a关系中,有一个单独的引用需要被销毁。Perl 要么在引用计数减少时自动执行此操作,要么您必须自己执行此操作。

于 2012-09-15T10:33:58.127 回答
1

has-a 关系是一个对象简单地存储另一种类型的对象的关系。就像一个对象可以存储一个数字或字符串一样,它也可以存储另一个对象。真的没有比这更复杂的了。

package MyClass;
sub new {
  my $class = shift;
  my $obj = bless {}, $class;
  $obj->{some_thing_else} = SomeOtherClass->new;
}

is-a 关系是继承的另一个名称。

package SomeSubClass;
use parent 'SomeParentClass'; 
# older ways to do this are 'use base' and pushing on @ISA.

这些概念与 Perl 相关,没有什么特别之处,但我在上面展示了 Perl 示例。

您的第一个示例只是一个标准的 Perl 类。你的第二个例子是一个有关系。您的代码都没有摘录继承示例(is-a)。

[顺便说一下,bless在你的方法中调用时new,你应该从 new 的第一个参数中获取类名(如上所示),否则,人们将无法从你的类继承而不覆盖new. 如果我调用SomeSubClass->new,并且 SomeSubClass 从 SomeParentClass 继承了新的,并且 SomeParentClass 做了你刚才所做的事情,那么我将获得 SomeParentClass 类的对象,而不是 SomeSubClass。(当然,也许你不希望你的类是可继承的,或者你希望 new 被覆盖,无论出于何种原因。)]

Perl 的对象系统非常简单,你可以用它做任何你想做的事情。但是社区正在转向一种叫做 Moose 的东西,这是一个 CPAN 模块,它提供了一个构建在上面的更复杂的对象系统。

于 2012-09-15T08:21:59.213 回答
1

继承是'is-a'的关系,类/包具有的任何属性(带有' has'的驼鹿)或受祝福对象的哈希键(例如,假设对象被祝福成hashref)是has-a

于 2012-09-15T08:23:04.493 回答