Почему дочерний класс вызывает свои функции родительского класса, а также свои собственные?

#perl #oop #inheritance #instantiation #overriding

#perl #ооп #наследование #создание экземпляра #переопределение

Вопрос:

Я начал осваивать наследование в Perl / Moose, но я начинаю сталкиваться с некоторыми проблемами.

Например, порядок сборки унаследованных объектов, кажется, имеет смысл, но наследование, похоже, работает не так, как я ожидаю—

Если мои вызовы базового класса BUILD, все подклассы будут вызывать свою СБОРКУ, а также СБОРКУ базового класса, но это не ограничивается функцией сборки moosey .

Если я определяю функцию init() в базовом классе и вызываю ее из СБОРКИ базового класса, вместо init() базового класса вызывается init() подклассов

o_O

Для краткости предположим, что у нас есть следующие объектные конструкции:

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

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

Теперь создайте экземпляр дочернего класса

 my $child = ChildClass->new();
  

Результирующий порядок вызовов из new() выглядит для меня следующим образом на основе моего вывода отладки

 BaseClass->BUILD()
BaseClass->init() <--- this calls ChildClass::init
ChildClass->BUILD()
ChildClass->init() <--- this calls ChildClass::init too!
  

Я понимаю, что они оба вызывают BUILD а-ля Moose. Хорошо. Наверное, я неправильно понимаю, почему BaseClass в этом случае не вызывает свой собственный BaseClass::init или, альтернативно, почему ChildClass не просто вызывает свой собственный ChildClass::BUILD .

Нужно ли мне специально «переопределять» эти функции с помощью модификатора функции Moose «переопределять»?

Тогда, если я добавлю BUILDARGS в микс, это станет еще интереснее, потому что вопрос в том, кто получает аргументы, переданные в new(), и что, если у базового класса есть роли, связанные с ним?

 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:

Я предполагаю, что у вас есть функция сборки в каждом классе, немного похожая

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

Moose обрабатывает BUILD иначе, чем Perl обычно обрабатывает вызовы методов. Когда вы вызываете init в своих методах СБОРКИ, Perl будет использовать свое обычное разрешение метода и найдет дочерний метод init, поскольку он маскирует родительский метод init . Затем дочерний метод может вызывать родителей с $self->SUPER::init() помощью модификатора ‘override’ Moose и super() является просто модифицированным способом использования SUPER:: .

Если вы вызываете init только в методе сборки вашего родительского класса, вы можете использовать любой из стандартных модификаторов метода Moose, таких как ‘before’, ‘after’, ‘around’ или ‘override’, чтобы контролировать, когда инициализация дочернего класса вызывается относительно инициализации родительского.

Если, с другой стороны, вы хотите, чтобы инициализация каждого класса вызывалась при запуске сборки этого класса, вы можете специально попросить Perl пропустить стандартный поиск метода и использовать метод указанного класса:

 package ParentClass;

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

package ChildClass;

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