开发者

How can I make an object in my parent class but bless it into my child class in Perl?

开发者 https://www.devze.com 2022-12-15 04:42 出处:网络
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

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号