【问题标题】:Why doesn't $class->SUPER::new call the constructors of all parent classes when using multiple inheritance?为什么$class->SUPER::new在使用多重继承时不调用所有父类的构造函数?
【发布时间】:2017-08-10 15:29:24
【问题描述】:

我正在尝试在 Perl 中使用多重继承,但我不知道如何从子构造函数中调用多个父构造函数。

下午:

package A;
use Carp qw (croak);
use strict;
use warnings;

sub new {
    my $class = shift;
    print "This is A new\n";
    my $self->{DEV_TYPE} = shift || "A";
    bless($self, $class);
    return $self;
}

sub a_func{
    print "This is A func\n";
}

1;

下午:

package B;
use Carp qw (croak);
use strict;
use warnings;

sub new {
    my $class = shift;
    print "This is B new\n";
    my $self->{DEV_TYPE} = shift || "B";
    bless($self, $class);
    return $self;
}

sub b_func{
    print "This is B func\n";
}

1;

下午:

package C;
use Carp qw (croak);
use strict;
use warnings;
eval "use A";
die $@ if $@;
eval "use B";
die $@ if $@;
our @ISA = ("A","B");

sub new {
    my $class = shift;
    my $self = $class->SUPER::new(@_);
    print "This is C new\n";
    $self->{DEV_TYPE} = shift || "C";
    bless($self, $class);
    return $self;
}

sub c_func{
    print "This is C func\n";
}

1;

C::new 中,$class->SUPER::new 不会调用 B 的构造函数。如果我使用 $class->B::new(@_); 显式调用它,则会收到错误消息

在 C.pm 中无法通过包“B”定位对象方法“new”

我做错了什么?

【问题讨论】:

  • $class->SUPER::new(@_) 只会选择@ISA 中的一项,否则它需要返回一组对象引用(一个引用用于A->new(),一个引用用于B->new()
  • 另见perlobjmro中的“方法解析顺序”
  • 您可以强制它使用my $selfB = do { local @ISA = ("B"); $class->SUPER::new(@_) }; 调用B 类构造函数,但我不知道这是否是个好主意

标签: perl multiple-inheritance


【解决方案1】:

$class->SUPER::new 总是调用A::new,因为在@ISA 中A 在B 之前。请参阅 perlobj 中的method resolution order

当一个类有多个父类时,方法查找顺序变得更加复杂。

默认情况下,Perl 对方法进行深度优先从左到右的搜索。这意味着它从@ISA 数组中的第一个父项开始,然后搜索其所有父项、祖父母等。如果找不到该方法,则转到原始类的@ISA 数组中的下一个父项并从那里搜索。

这意味着$class->SUPER::new 只会调用其中一个父构造函数。如果您在两个父类中都有需要从子类运行的初始化逻辑,请将其移动到单独的方法中,如this post 中所述。


当您使用$class->B::new 显式调用B::new 时,您会得到

在 C.pm 中无法通过包“B”定位对象方法“new”

因为use B 正在加载core module B 而不是您的模块。你应该重命名你的模块。


请注意,最好使用parent pragma 而不是手动设置@ISA,例如

use parent qw(Parent1 Parent2);

parent 负责加载父模块,因此您可以删除关联的 use 语句(顺便说一下,您不应该是 evaling)。

【讨论】:

  • 谢谢,B 问题解决了 - 现在是 D。但是,即使我将其更改为使用 parent,当我运行 my $self = $class->SUPER::new(@_); 时它仍然不会成为 D 承包商
  • @OmerLevy 查看我的编辑。只会调用一个new 方法。如果你想同时调用两者,你​​应该将初始化移动到单独的 subs 中,如 here 所述。
猜你喜欢
  • 2014-10-11
  • 1970-01-01
  • 2021-11-13
  • 2021-11-23
  • 2013-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多