6

我已经看到了两种new在派生类中实现该方法的方法。

方法一:

sub new {
    my $invocant = shift;
    my $class   = ref($invocant) || $invocant; 
    my $self = {};
    bless($self, $class);
    $self = $self->SUPER::new( @_ );
    return($self);
}

方法二:

sub new {
  my $self = shift;
  my $class = ref($self) || $self;
  return $self if ref $self;
  my $base_object = $class->SUPER::new(@_);
  return bless ($base_object, $class);
}

我不确定我理解有什么区别。谁能解释一下?


从您的评论和回答中,我可以看出这ref()部分很糟糕。

但是使用SUPER::new(@_)呢?在第一个示例中,hashref 被祝福到派生类中,然后调用该对象的SUPER'snew并将其保存到同一个对象中。

另一方面,在第二个示例中,基对象是从类的SUPERsnew方法创建的,并被祝福到新类中。

这两种方式有什么区别?看起来第一个用基础对象覆盖了对象。第二个似乎是“双重祝福”。我很困惑。

4

2 回答 2

9

为什么不只是:

sub new {
    my $class = shift;
    my $self = $class->SUPER::new(@_);
    $self->do_some_additional_init();
    return $self;
};

- 唯一的例外是层次结构中最深的基类,它应该调用bless $self, $class;或者可能调用my $self = fields::new($class);,以防万一use fields

于 2012-06-08T19:57:36.853 回答
6

更新

你问:

这两种方式有什么区别?看起来第一个用基础对象覆盖了对象。第二个似乎是“双重祝福”。我很困惑。

振作起来。您展示的两种方法中的每一种本身都令人困惑,并且都不应该被效仿。

方法一祝福 DerivedClass 类的对象存在,然后使用该对象调用某个 AncestorClass 的分配器/构造器,替换自身。现在,AncestorClass::new 可能也使用了不幸的ref($yuck) || $yuck习语,这意味着新对象将被祝福进入 DerivedClass。因此,一个 DerivedClass 对象用于构造另一个来替换它。可疑。

如果接收者是一个对象,方法二返回它的接收者($self)。(注意,ref($self)当它只需要检查一次时,会检查两次。)也就是说,在方法二下$o->new()返回完全相同。$o如果接收者不是对象而是类名,也就是说,如果我们调用了DerivedClass->new,则调用 AncestorClass::new。但是超类'方法的第一个参数是'DerivedClass',想必超类并没有硬编码它的blessed包名,所以后面的重新加持是没有意义的。

只是不要担心这些例子。相反,请咨询perlobjperlootut以安全和理智地使用 SUPER。

原始答案

啊,我的眼睛!

正如 daxim 所评论的,方法一是一种令人反感的方法,它允许人们从与现有对象相同的类中构造一个对象:

my $o1 = MethodOne->new();
my $o2 = $o1->new();        # $o2 is a clone of $o1.  No, wait, it isn't!
                            # It's a brand new, "empty" object.  Ha,
                            # fooled you.

方法二是(我认为)这种令人困惑的做法的解决方法。如果被调用 ,您的方法二将返回完全相同的对象。new()

my $o1 = MethodTwo->new();
my $o2 = $o1->new();         # $o2 is a new MethodTwo.  No, wait, it isn't!
                             # It's a brand new object.  No, wait, it isn't!
                             # It's a /exactly the same object/ as $o1.  Ha,
                             # fooled you.

也不要使用。:) 可能在某些应用程序中,上述任何一种语义都非常有意义。我只是不会new()在这些应用程序中命名该方法......

于 2012-06-08T15:20:50.863 回答