I am trying to initialize a base class and a subclass without having to copy the constructor. This is what I got:
tstbase.pm:
package tstbase;
use Exporter qw(import);
our @EXPORT = qw(&new);
my %config = (
"class" => "tstbase",
);
sub new {
my $class = shift;
my $self;
$self->{"name"} = $config{"class"};
bless ($self, $class);
return $self;
};
1;
tstsubclass.pm:
package tstsubclass;
use tstbase;
my %config = (
"class" => "tstsubclass",
);
1;
tst.pl:
#!/usr/bin/perl
use tstsubclass;
my $baseobj = tstbase->new;
print "Testbase ".$baseobj->{"name"}."\n";
my $subobj = tstsubclass->new;
print "Testsubclass ".$subobj->{"name"}."\n";
The outout of tst.pl is
Testbase tstbase
Testsubclass tstbase
but I am looking for
Testbase tstbase
Testsubclass tstsubclass
which I get when I copy the "sub new { .. }" routine over to tstsubclass.pm. Is there a way to avoid that overhead? I have tried all combinations of my %config / our %config and exporting %config with no success.
Any help is greatly appreciated
Best,
Marcus
Your constructor is inherited, so that's working fine. What's not working is your use of %config
, which exists separately in each package. Because you're calling the constructor defined in your base class, that version of %config
is used. In your specific case, the config hash is unnecessary, since you can just initialize the name
member by using the $class
variable passed in to your constructor:
sub new {
my $class = shift;
my $self = { }; # initialize the object as a reference to an empty hash
$self->{"name"} = $class;
bless ($self, $class);
return $self;
};
This will work (although it's unnecessary; you can always get the class of an object using Scalar::Util::blessed
).
But the more general question appears to be about how to use class-specific configuration information in an inherited constructor. One way to do it would be to use a separate initialization step which can be overridden in the child class.
package tstbase;
# we don't use Exporter for OO code; exporting methods is highly counterproductive.
# we should also turn on strict and warnings.
use strict;
use warnings;
my %config = (
"class" => "tstbase",
);
sub new {
my $class = shift;
my $self;
bless $self, $class;
$self->_init( %config );
return $self;
};
sub _init {
my $self = shift;
my %args = @_;
$self->{name} = $args{class};
}
1;
And then:
package tstsubclass;
use parent 'tstbase'; # we have to say what class we're extending
my %config = (
"class" => "tstsubclass",
);
sub _init {
my $self = shift;
$self->SUPER::_init( %config );
}
1;
In this case, your subclass's _init
method will get called by the constructor in the parent class, which calls the parent class's _init
method, but passing in its local %config
.
An easier way to handle this would be to use mixins, or Moose roles.