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