I am trying to use multiple inheritance in Perl, but I can't figure out how to call multiple parent constructors from the child constructor.
A.pm:
package A;
use Carp qw (croak);
use strict;
use warnings;
sub new {
my $class = shift;
print "This is A new\n";
my $self->{DEV_TYPE} = shift || "A";
bless($self, $class);
return $self;
}
sub a_func{
print "This is A func\n";
}
1;
B.pm:
package B;
use Carp qw (croak);
use strict;
use warnings;
sub new {
my $class = shift;
print "This is B new\n";
my $self->{DEV_TYPE} = shift || "B";
bless($self, $class);
return $self;
}
sub b_func{
print "This is B func\n";
}
1;
C.pm:
package C;
use Carp qw (croak);
use strict;
use warnings;
eval "use A";
die $@ if $@;
eval "use B";
die $@ if $@;
our @ISA = ("A","B");
sub new {
my $class = shift;
my $self = $class->SUPER::new(@_);
print "This is C new\n";
$self->{DEV_TYPE} = shift || "C";
bless($self, $class);
return $self;
}
sub c_func{
print "This is C func\n";
}
1;
In C::new
, $class->SUPER::new
doesn't call the constructor for B. If I call it explicitly with $class->B::new(@_);
, I get the error
Can't locate object method "new" via package "B" at C.pm
What am I doing wrong?
$class->SUPER::new
always calls A::new
because A comes before B in @ISA
. See method resolution order in perlobj:
When a class has multiple parents, the method lookup order becomes more complicated.
By default, Perl does a depth-first left-to-right search for a method. That means it starts with the first parent in the
@ISA
array, and then searches all of its parents, grandparents, etc. If it fails to find the method, it then goes to the next parent in the original class's@ISA
array and searches from there.
This means that $class->SUPER::new
will only call one of the parent constructors. If you have initialization logic in both parent classes that needs to be run from the child, move it into separate methods as described in this post.
When you explicitly call B::new
with $class->B::new
, you get
Can't locate object method "new" via package "B" at C.pm
because use B
is loading the core module B instead of your module. You should rename your module.
Note that it's better to use the parent
pragma instead of setting @ISA
manually, e.g
use parent qw(Parent1 Parent2);
parent
takes care of loading the parent modules, so you can drop the associated use
statements (which you shouldn't be eval
ing, by the way).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With