为什么childClass调用它的parentClass函数和它们自己的?

时间:2011-10-21 18:55:30

标签: perl oop inheritance instantiation override

我开始在Perl / Moose中获得继承权,但我开始遇到一些粗糙的问题。

例如,继承对象的构建顺序似乎有意义,但继承似乎并不像我期望的那样 -

如果我的baseClass调用BUILD,所有子类将调用它们的BUILD以及baseClass的BUILD,但这不仅限于moosey BUILD函数。

如果我在baseClass中定义一个函数init(),并从baseClass BUILD调用它,则调用子类init()而不是baseClass的'init()

O_O

为简洁起见,我们假设我们有以下对象构造:

BaseClass
    ::BUILD --> call init()
    ::init  --> do BaseStuff 

ChildClass extends BaseClass
    ::BUILD --> call init()
    ::init  --> do ChildStuff

现在实例化childClass

my $child = ChildClass->new();

根据我的调试输出

,new()产生的调用顺序对我来说就是这样
BaseClass->BUILD()
BaseClass->init() <--- this calls ChildClass::init
ChildClass->BUILD()
ChildClass->init() <--- this calls ChildClass::init too!

我知道他们都叫做BUILD a la Moose。精细。我想我误解了为什么baseClass在这种情况下不会调用它自己的baseClass :: init,或者为什么childClass不会只调用它自己的childClass :: BUILD。

我是否需要使用Moose“覆盖”功能修饰符专门“覆盖”这些功能?

然后如果我把BUILDARGS混合在一起,它会变得更有趣,因为问题是谁将参数传递给new()以及如果baseClass有与之关联的角色怎么办?

BaseClass (has role CanSee and has seesWith() attribute)
BaseClass (has role NameTag and has name() attribute)
ChildClass (has role FavoriteColor and has color() attribute)

my $child = ChildClass->new( name => 'Jane', seesWith => 'eyes', color => 'red');

然后

ChildClass
        ::BUILDARGS --> 
             ($orig,$class,$args) = @_;
             return $class->$orig(@_);

在这种情况下哪个是$ class?

别告诉我,我必须覆盖BUILDARGS ... lol

1 个答案:

答案 0 :(得分:3)

我假设你在每个类中都有一个BUILD函数,有点像

sub BUILD {
    my $self = shift;
    ...
    $self->init();
    ...
}

Moose以不同的方式处理BUILD,Perl通常会处理方法调用。当您在BUILD方法中调用init时,Perl将使用它的正常方法解析并找到子进程的init方法,因为它掩盖了父进程的init方法。然后,孩子的方法可以使用$self->SUPER::init(),Moose的“覆盖”修饰符调用父母,super()只是修改了使用SUPER::的方法。

如果你只在你父类的BUILD方法中调用init,你可以使用任何标准的Moose方法修饰符,比如'before','after','around'或'override'来控制子类的init被调用的时间相对于父母的初始。

另一方面,如果你希望在运行该类的构建时调用每个类的init,你可以特别要求Perl跳过标准方法查找并使用指定类的方法:

package ParentClass;

sub BUILD {
    my $self = shift;
    ...
    $self->ParentClass::init();
    ...
}

package ChildClass;

sub BUILD {
    my $self = shift;
    ...
    $self->ChildClass::init();
    ...
}