Perl:如何在多重继承中调用特定方法?

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中获取两种方法而不改变基类的顺序?

谢谢!

zdi*_*dim 5

您可以重写Child类中所需的方法,从而调度到完全合格的调用

package Child;

...

sub baz 
{
    shift;
    Parent2::baz(@_);
}

...
Run Code Online (Sandbox Code Playgroud)

将其添加到您的代码中后,可以根据需要进行打印Baz from Parent2

这是“增强”这些类的接口的相当手动的方法,这些类显然不是为多重继承而设计的。但是您所描述的情况确实令人不快,必须执行类似@ISA操作或对特定操作进行硬编码。

对于更复杂的需求,请参见mro,这与所有这些都明确相关。它支持自省,因此您可以在运行时做出决定。您仍然需要这样做Child::baz()

您是否可以偶然更改设计并且使用多重继承?


Dav*_*man 4

如果您有权修改基类,则可以通过更改为$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