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
@ISAarray, 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@ISAarray 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 evaling, 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