在perl中调用基构造函数

在perl中调用基构造函数,perl,oop,constructor,base,Perl,Oop,Constructor,Base,在Perl中,从类构造函数调用基构造函数的正确方法是什么 我见过这样的语法: my $class = shift; my $a = shift; my $b = shift; my $self = $class->SUPER::new($a, $b); return $self; 这是正确的吗?如果我们有几个父类呢。例如,像这样的类: package Gamma; use base Alpha; use base Beta; sub new { # Cal

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

我见过这样的语法:

 my $class = shift; 
 my $a = shift; 
 my $b = shift;
 my $self = $class->SUPER::new($a, $b);
 return $self;
这是正确的吗?如果我们有几个父类呢。例如,像这样的类:

 package Gamma;
 use base Alpha;
 use base Beta;

 sub new
 {
   # Call base constructors...
 }
 1;

如果您的构造函数所做的只是调用父构造函数(如您的示例中所示,您根本不需要编写父构造函数。只需将其忽略,就会调用父构造函数;您只需确保对象的类型正确:

package Parent;
use strict;
use warnings;

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

    # do something with @args

    return bless {}, $class;
}
1;
如果您使用上述代码并使用
use parent'parent';
声明了
子类
,则父构造函数将正确构造子类

如果您需要在子对象中添加一些属性,那么您所拥有的基本上是正确的:

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;
但是,当您将多重继承引入到混合中时,您需要在每一步中决定正确的操作。这意味着每个类都有一个自定义构造函数,它决定如何将Parent1和Parent2的属性合并到子类中,然后最终将生成的对象添加到子类中。这个复杂问题仍然存在多重继承是一个糟糕的设计选择的原因有很多。您是否考虑过重新设计您的对象继承权,可能是通过将某些属性移动到角色中?此外,您可能希望使用对象框架来完成一些繁忙的工作,例如。现在很少需要编写自定义构造函数

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;
}

(最后,应该避免使用变量
$a
$b
;在Perl中,它们的处理方式不同,因为它们是排序函数和其他一些内置函数中使用的变量。)

这个问题就是为什么有些人建议不要在
新的
方法中执行任何有趣的操作。
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;
}
对于使用多重继承可能会遇到的复杂情况,以太是正确的。您仍然需要知道,
父亲::\u init
不会覆盖母亲::\u init
首先做出的任何决定。从那里开始调试只会变得更加复杂和困难


我支持的建议,它的接口包括比我上面的示例更好的对象创建和初始化分离,而我的示例通常只起作用。

当使用多重继承时,默认的方法解析顺序是低于标准。我强烈建议您添加

use mro 'c3';
并调用链中的下一个构造函数,使用

sub new {
   my ($class) = @_;
   return $class->next::method(@_);
}
Alpha和Beta也必须这样做才能起作用


Ref:

谢谢,这似乎是将我当前的代码转换为可用代码的最简单方法。