I have two classes: a base class, Foo::Base and a derived class, Foo::Base::Sub
. I want to have Foo::Base::Sub
do some type and data checking on the constructor`s argument--a hash--before blessing it. I've tried overriding Foo::Base->new
's constructor, doing the checks and then calling Foo::Base->new
(since the code would be exactly the same):
package Foo::Base::Sub;
sub new {
...check argument's type and data...
Foo::Base->new(%my_hash)
}
The problem is that by calling Foo::Base
's constructor, the hash will now be blessed as a Foo::Base object and not a Foo::Base::Sub object. The obvious solution is simply to put the code from Foo::Base::new
into Foo::Base::Sub::new
but then I'm repeating code. The other thing is 开发者_开发知识库that Foo::Base is not mine--thus I'd like to avoid having to modify it after the module has loaded or forking it unnecessarily.
It seems to me that this problem must have come up before and so there must be a canonical solution. Moreover, it really touches on type coercion which is generally not an issue Perl.
So is there a simple modification or am I going about this the wrong way?
A standard Perl idiom is to use SUPER
to call up the inheritance chain:
@Foo::Base::Sub::ISA = qw(Foo::Base);
sub new {
my $package = shift;
my $self = $package->SUPER::new();
# Other subconstructor stuff here
return $self;
}
As noted in the comments, Foo::Base
's constructor must use the two-argument form of bless
:
sub new {
my $package = shift;
my $self = bless {}, $package;
# Other superconstructor stuff here
return $self;
}
When the superclass' constructor is called, $package
will be the subclass.
I'm used to split this to two parts, new
and init
.
package Foo::Base;
sub new {
my $class = shift;
my $self = bless {}, $class;
return $self->init(@_);
}
sub init {
my ($self, @params) = @_;
# do something initialization and checks
return $self;
}
package Foo::Sub;
use base 'Foo::Base';
sub init {
my ($self, @params) = @_;
# do something initialization and checks
$self = $self->SUPER::init(@params);
# do something other if you wish
return $self;
}
Note that 'Foo::Sub'
doesn't implement new
constructor.
You might want to look at the various ways of invoking super. The SUPER module may work although I havent tried it myself.
精彩评论