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

Perl: How to call a specific method in multiple inheritance?

我在 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;

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

Child: 这使用了上面的两个 parent 包。

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;

主要:

use strict;
use warnings;
use Child;

my $childObj = new Child;

$childObj->Parent2::foo();

输出:

 Foo from Parent 2 
 Baz from Parent 1 

我的分析:

从输出中可以清楚地看出,child object 被传递给了 parent2 的 foo 方法,并且从该 foo 方法调用了 baz 方法。它首先检查 Child 包中的 baz 方法,因为我用 child object 调用它。由于 baz 方法不在 child 包中,它会检查基础 class 中的方法。 Parent1 是 Child 的第一个碱基 class。因此,它找到 Parent1 中的方法并调用 Parent1.

中的 baz 方法

我的问题:

是否可以调用Parent2的baz方法而不改变child中baseclass的顺序?

我的预期输出:

 Foo from Parent 2 
 Baz from Parent 2

上面的例子只是我实际问题的类比。我无权修改 Base classes。我只有权限修改Childclass。那么,是否可以更改 child class 以使其从 Parent2 中获取两种方法而不更改基础 classes 的顺序?

谢谢!

您可以为首选方法创建别名。通常这是一个坏主意,除非您知道自己在做什么。看看 perldoc perlmod #Symbol Tables.

将您的主文件更新为:

 use strict;
 use warnings;
 use Child;

 my $childObj = new Child;

 $childObj->Parent2::foo();

 print "------\n";
 no warnings; # Otherwise will complain about 'Name "Child::baz" used only once: possible typo'
 # Create an alias
 *Child::baz = *Parent2::baz;
 use warnings;
 $childObj->Parent2::foo();

输出

Foo from Parent 2
Baz from Parent 1
------
Foo from Parent 2
Baz from Parent 2

您可以覆盖 Child class 中所需的方法,调度到完全限定的调用

package Child;

...

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

...

将此添加到您的代码后,它会根据需要打印,Baz from Parent2

这是 "augment" 这些 classes 的接口的一种相当手动的方法,这些 classes 显然不是为多重继承而设计的。但是你描述的情况确实令人不快,必须做这样的事情,或者硬编码特定的 @ISA 操作。

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

您能否更改设计并且使用多重继承?

如果您有权修改基数 类,您可以通过将 $self->baz() 更改为 Parent2::baz($self) 来完成此操作,但您说您不能这样做。

既然这不是一个选项,您如何看待 暂时 改变基数 类 的顺序?在 Perl 中,base 类 的列表实际上只是每个包中名为 @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;

输出:

In localized block
foo2
baz2
Block has exited
foo2
baz1

因此您可以看到,这在具有本地化 @ISA 的块内提供了您想要的输出,然后在块退出时恢复原始行为。

此外,在结束时附注:在 Perl 中使用 new Child 称为 "indirect object notation",通常被认为是 。我建议改用 Child->new