jay*_*han 7 perl inheritance package subroutine
我在perl中有一个包,它使用另外两个包作为它的基础.
Parent1:
package Parent1;
use strict;
use warnings;
sub foo
{
my $self = shift;
print ("\n Foo from Parent 1 ");
$self->baz();
}
sub baz
{
my $self = shift;
print ("\n Baz from Parent 1 ");
}
1;
Run Code Online (Sandbox Code Playgroud)
家长2:
package Parent2;
use strict;
use warnings;
sub foo
{
my $self = shift;
print ("\n Foo from Parent 2 ");
$self->baz();
}
sub baz
{
my $self = shift;
print ("\n Baz from Parent 2 ");
}
1;
Run Code Online (Sandbox Code Playgroud)
子:这使用上面的两个父包.
package Child;
use strict;
use warnings;
use base qw(Parent1);
use base qw(Parent2);
sub new
{
my $class = shift;
my $object = {};
bless $object,$class;
return $object;
}
1;
Run Code Online (Sandbox Code Playgroud)
主要:
use strict;
use warnings;
use Child;
my $childObj = new Child;
$childObj->Parent2::foo();
Run Code Online (Sandbox Code Playgroud)
输出:
Foo from Parent 2
Baz from Parent 1
Run Code Online (Sandbox Code Playgroud)
我的分析:
从输出中可以清楚地看到,子对象被传递给parent2的foo方法,并且从那个foo方法,它正在调用baz方法.它首先检查Child包中的baz方法,因为我用子对象调用它.因为,baz方法不在子包中,所以它检查基类中的方法.Parent1是Child的第一个基类.因此,它在Parent1中找到方法并调用Parent1的baz方法.
我的问题:
是否可以在不改变子节点中基类的顺序的情况下调用Parent2的baz方法?
我的预期输出:
Foo from Parent 2
Baz from Parent 2
Run Code Online (Sandbox Code Playgroud)
上面的例子只是我实际问题的一个类比.我没有权限修改Base类.我只能修改Child类.那么,是否有可能以这样一种方式改变子类:它从Parent2中获取两种方法而不改变基类的顺序?
谢谢!
您可以重写Child类中所需的方法,从而调度到完全合格的调用
package Child;
...
sub baz
{
shift;
Parent2::baz(@_);
}
...
Run Code Online (Sandbox Code Playgroud)
将其添加到您的代码中后,可以根据需要进行打印Baz from Parent2。
这是“增强”这些类的接口的相当手动的方法,这些类显然不是为多重继承而设计的。但是您所描述的情况确实令人不快,必须执行类似@ISA操作或对特定操作进行硬编码。
对于更复杂的需求,请参见mro,这与所有这些都明确相关。它支持自省,因此您可以在运行时做出决定。您仍然需要这样做Child::baz()。
您是否可以偶然更改设计并且不使用多重继承?
如果您有权修改基类,则可以通过更改为$self->baz()来做到这一点Parent2::baz($self),但您说您无法这样做。
既然这不是一个选择,那么您对暂时改变基类的顺序有何看法?在 Perl 中,基类列表实际上只是@ISA每个包中命名的数组,因此您可以使用local在块中创建该数组的本地化副本:
#!/usr/bin/env perl
use strict;
use warnings;
use 5.010;
package Parent1;
sub foo { say 'foo1'; $_[0]->baz; }
sub baz { say 'baz1'; }
package Parent2;
sub foo { say 'foo2'; $_[0]->baz; }
sub baz { say 'baz2'; }
package Child;
use base qw( Parent1 Parent2 );
sub new { return bless {} }
package main;
my $childobj = Child->new;
{
local @Child::ISA = qw( Parent2 Parent1 );
say 'In localized block';
$childobj->Parent2::foo;
}
say 'Block has exited';
$childobj->Parent2::foo;
Run Code Online (Sandbox Code Playgroud)
输出:
In localized block
foo2
baz2
Block has exited
foo2
baz1
Run Code Online (Sandbox Code Playgroud)
因此您可以看到,这在块内提供了您所需的本地化输出@ISA,然后当块退出时恢复原始行为。
另外,结束语中的一个旁注:new Child在 Perl 中使用被称为“间接对象表示法”,它通常被认为是一件坏事。我建议使用Child->new。