关于构造函数:如何在父类中创建一个对象,但是将它保存到Perl中的子类中?

How can I make an object in my parent class but bless it into my child class in Perl?

我有两个类:基类foo::base和派生类Foo::Base::Sub。我想让Foo::Base::Sub对构造函数的参数(散列)进行一些类型和数据检查,然后再进行修改。我尝试重写Foo::Base->new的构造函数,进行检查,然后调用Foo::Base->new(因为代码完全相同):

1
2
3
4
5
6
package Foo::Base::Sub;

sub new {
    ...check argument's type and data...
    Foo::Base->new(%my_hash)
}

问题是,通过调用Foo::Base的构造函数,散列现在将被视为foo::base对象而不是foo::base::sub对象。显而易见的解决方案是将来自Foo::Base::new的代码放入Foo::Base::Sub::new中,但随后我要重复代码。另一件事是foo::base不是我的——因此我希望避免在模块加载或不必要地分叉之后修改它。

在我看来,这个问题一定是以前出现的,所以一定有一个规范的解决方案。此外,它还涉及类型强制,这通常不是Perl的问题。

那么,有没有简单的修改,或者我这样做是错误的?


标准的Perl习惯用法是使用SUPER调用继承链:

1
2
3
4
5
6
7
8
9
10
11
@Foo::Base::Sub::ISA = qw(Foo::Base);

sub new {
    my $package = shift;

    my $self = $package->SUPER::new();

    # Other subconstructor stuff here

    return $self;
}

如注释所述,Foo::Base的构造函数必须使用bless的两种参数形式:

1
2
3
4
5
6
7
8
9
sub new {
    my $package = shift;

    my $self = bless {}, $package;

    # Other superconstructor stuff here

    return $self;
}

当调用超类的构造函数时,$package将是子类。


我习惯于把这个分成两部分,newinit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package Foo::Base;

sub new {
  my $class = shift;
  my $self = bless {}, $class;
  return $self->init(@_);
}

sub init {
  my ($self, @params) = @_;
  # do something initialization and checks
  return $self;
}

package Foo::Sub;

use base 'Foo::Base';

sub init {
  my ($self, @params) = @_;
  # do something initialization and checks
  $self = $self->SUPER::init(@params);
  # do something other if you wish
  return $self;
}

注意,'Foo::Sub'不实现new构造函数。


您可能希望了解调用super的各种方法。超级模块可能会工作,尽管我自己没有尝试过。


虽然"超级"答案确实描述了您在这里想要什么,但是您可以(在更一般的情况下)通过这样的操作调用任意包中的方法代码:

1
2
 $object = Foo::Class->new(...);
 $object->Bar::Class::method(@args);

Bar::Class::方法将正常进行,如下所示:

1
2
3
 package Bar::Class;
 sub method {
   my ($self, @args) = @_;

只有$self和平常不同。当然,做这个而不是做很多事情可能是你做错了什么的一个信号。

还可以比较next和perl 5.10的"mro"。