在perl中调用基础构造函数

Zit*_*rax 20 oop perl constructor base

从Perl中的类构造函数调用基础构造函数的正确方法是什么?

我看过这样的语法:

 my $class = shift; 
 my $a = shift; 
 my $b = shift;
 my $self = $class->SUPER::new($a, $b);
 return $self;
Run Code Online (Sandbox Code Playgroud)

它是否正确 ?如果我们有几个父类怎么办?例如,像这样的类:

 package Gamma;
 use base Alpha;
 use base Beta;

 sub new
 {
   # Call base constructors...
 }
 1;
Run Code Online (Sandbox Code Playgroud)

Eth*_*her 33

如果您的所有构造函数都在调用父构造函数(如您的示例所示,您根本不需要编写一个.只需将其保留并调用父项;您只需要确保该对象被祝福正确的类型:

package Parent;
use strict;
use warnings;

sub new
{
    my ($class, @args) = @_;

    # do something with @args

    return bless {}, $class;
}
1;
Run Code Online (Sandbox Code Playgroud)

如果您使用上面的代码并使用Child声明的类,use parent 'Parent';则Parent构造函数将正确构造子代.

如果你需要在Child中添加一些属性,那么你所拥有的内容基本上是正确的:

package Child;
use strict;
use warnings;

use parent 'Parent';

sub new
{
    my ($class, @args) = @_;

    # possibly call Parent->new(@args) first
    my $self = $class->SUPER::new(@args);

    # do something else with @args

    # no need to rebless $self, if the Parent already blessed properly
    return $self;
}
1;
Run Code Online (Sandbox Code Playgroud)

但是,当你将多个继承带入混合时,需要决定在每一步中做正确的事情.这意味着每个类的自定义构造函数决定如何将Parent1和Parent2的属性合并到子项中,然后最终将生成的对象保存到Child类中.这种复杂性是多重继承是一个糟糕的设计选择的众多原因之一.您是否考虑过重新设计对象层次结构,可能是将某些属性转换为角色?此外,您可能希望使用对象框架来取消一些繁忙的工作,例如Moose.现在很少需要编写自定义构造函数.

(最后,你应该避免使用变量$a$b;它们在Perl区别对待,因为它们在排序函数中使用的变量和其他一些内置插件.)


Ven*_*tsu 20

这个问题就是为什么有人建议不要在你的new方法中做任何有趣的事情. new期望创建并返回一个有福的引用,很难让一个系统处理来自不同父类的同一对象的两次.

更清洁的选择是使用一个只创建对象的新方法,并调用另一个可以设置对象的方法.第二种方法的行为方式允许调用多个父方法.有效的new是你的分配器,这个其他方法是你的构造函数.

package Mother;
use strict;
use warnings;

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

sub _init {
    my ($self, @args) = @_;

    # do something

    return $self;
}

package Father;
use strict;
use warnings;

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

sub _init {
    my ($self, @args) = @_;

    # do something else

    return $self;
}

package Child;
use strict;
use warnings;

use base qw(Mother Father);

sub _init {
    my ($self, @args) = @_;

    # do any thing that needs to be done before calling base classes

    $self->Mother::_init(@args); # Call Mother::_init explicitly, SUPER::_init would also call Mother::_init
    $self->Father::_init(@args); # Call Father::_init explicitly, SUPER::_init would NOT call Father::_init

    # do any thing that needs to be done after calling base classes

    return $self;
}
Run Code Online (Sandbox Code Playgroud)

对于您可能通过使用多重继承而发现的并发症,以太是正确的.您仍然需要知道,Father::_init不会覆盖任何Mother::_init开始做出的决定.从那里开始调试只会变得更加复杂和困难.

我会推荐Moose的推荐,它的界面包括一个更好的分离对象创建和初始化,而不是上面通常只能工作的例子.


ike*_*ami 6

使用多重继承时,默认方法解析顺序为低于标准.我强烈建议你添加

use mro 'c3';
Run Code Online (Sandbox Code Playgroud)

到模块,你用链接调用链中的下一个构造函数

sub new {
   my ($class) = @_;
   return $class->next::method(@_);
}
Run Code Online (Sandbox Code Playgroud)

Alpha和Beta必须做同样的工作.

参考:mro