http://qs321.pair.com?node_id=188985

bizzach has asked for the wisdom of the Perl Monks concerning the following question:

I have two classes, each has a constructor named new. I want to subclass the classes to make a new class. I need to call both parent constructors. However, how do I call the second constructor without clobbering by the data instance variables from first one? I can't seem to find this anywhere in the perldocs or in the Manning book.
Thanks,
Bizzach
package PClass1; use strict; use Carp; sub new { my $proto = shift; my $class = ref($proto) || $proto; my (%args) = @_; my $this = { _fs => $args{fs} || croak("You must supply a filesystem"), }; bless $this, $class; return $this; } ... package PClass2; use strict; sub new { my $proto = shift; my $class = ref($proto) || $proto; my (%args) = @_; my $this = { _hosts => $args{hosts}, }; bless $this, $class; return $this; } ...... package Subclass; use strict; use PClass1; use PClass2; our @ISA=qw(PClass1 PClass2); sub new { my ($class, %args) = @_; my $this = {}; bless $this, $class; $this = $class->PClass1::new(%args); #HOW DO I CALL THE SECOND CONSTRUCTOR HERE????? $this->init($this); return $this; }

Replies are listed 'Best First'.
Re: Multiple inheritance with multiple contructors?
by LanceDeeply (Chaplain) on Aug 09, 2002 at 20:36 UTC
    Try separating instantiation from initialization:
    package foo; use strict; sub new { print "foo::new\n"; my $self = bless( {}, shift ); $self->init(@_); return $self; } sub init { print "foo::init\n"; my $self = shift; my %args = ( foo=>undef, @_ ); $args{foo} = "foo" if ! defined $args{foo}; $self->foo($args{foo}); } sub foo { my $self = shift; $self->{_foo} = shift if @_; return $self->{_foo}; } 1;

    package bar; use strict; sub new { print "bar::new\n"; my $self = bless( {}, shift ); $self->init(@_); return $self; } sub init { print "bar::init\n"; my $self = shift; my %args = ( bar=>undef, @_ ); $args{bar} = "bar" if ! defined $args{bar}; $self->bar($args{bar}); } sub bar { my $self = shift; $self->{_bar} = shift if @_; return $self->{_bar}; } 1;

    package foobar; use strict; use foo; use bar; use vars(qw(@ISA)); @ISA=qw(foo bar); sub new { print "foobar::new\n"; my $self = bless( {}, shift ); $self->init(@_); return $self; } sub init { print "foobar::init\n"; my $self = shift; my %args = ( @_ ); $self->foo::init(%args); $self->bar::init(%args); } sub getFooBar { my $self = shift; return $self->foo() . $self->bar(); } 1;

    use strict; use foobar; main(); sub main() { my $fb = new foobar( foo=>'Lance', bar=>'Deeply' ); print $fb->getFooBar() ."\n"; }

      This works wonderfully and solves all my problems. I trully appreciate your help.
      Thanks,
      bizzach

Re: Multiple inheritance with multiple contructors?
by adrianh (Chancellor) on Aug 09, 2002 at 22:07 UTC

    If you really want to do this, here's one way. You just need to suck out the contents of your prototype hash and use it in the newly constructed object. For example:

    package Foo; sub new { my ($proto, %args) = @_; my $class = ref($proto) || $proto; $proto = ref($proto) ? $proto : {}; $proto->{Foo} = $args{Foo}; return bless {%$proto}, $class; } package Bar; sub new { my ($proto, %args) = @_; my $class = ref($proto) || $proto; $proto = ref($proto) ? $proto : {}; $proto->{Bar} = $args{Bar}; return bless {%$proto}, $class; } package FooBar; use base qw(Foo Bar); sub new { my ($proto, %args) = @_; my $self = $proto->Foo::new(%args)->Bar::new(%args); $self->{FooBar} = $args{FooBar}; return($self); }; package main; use Test::More 'no_plan'; my $fb = FooBar->new( Foo => 1, Bar => 2, FooBar => 3); isa_ok($fb, 'FooBar'); is($fb->{Foo}, 1, "Foo set"); is($fb->{Bar}, 2, "Bar set"); is($fb->{FooBar}, 3, "FooBar set");

    However, I would guess what you actually need is some sort of object delegation. Is your Subclass actually "kind of" PClass1 object and a "kind of" PClass2 object? Or does it just use them?

    If the latter, then you might want to take a look at Class::Delegation, Class::Facade and the section on Aggregation in perltoot.

    I think it was Bertrand Meyer who said something like "You have to be careful with multiple inheritence, otherwise you get a car-owner with four wheels". :-)

Re: Multiple inheritance with multiple contructors?
by twerq (Deacon) on Aug 09, 2002 at 18:03 UTC
    perltoot has a section called Multiple Inheritance that seems to be what you're looking for.

    --twerq

      I checked that. It has a section on inheriting a single constructor but it doesn't show how to call multiple constructors.

      I'm starting to think that what I'm trying to do is actually a hack and not good design. I'm really asking to inherit the constructor from multiple classes into a single subclass. Not really a supported OO concept.

Re: Multiple inheritance with multiple contructors?
by Anonymous Monk on Mar 16, 2012 at 18:23 UTC
    Alternate solution for reference:
    package PClass1; use strict; use Carp; sub new { my $proto = shift; my $class = ref($proto) || $proto; my (%args) = @_; my $this = { _fs => $args{fs} || croak("You must supply a filesystem"), }; bless $this, $class; return $this; } ... package PClass2; use strict; sub new { my $proto = shift; my $class = ref($proto) || $proto; my (%args) = @_; my $this = { _hosts => $args{hosts}, }; bless $this, $class; return $this; } ...... package Subclass; use strict; use PClass1; use PClass2; our @ISA=qw(PClass1 PClass2); sub new { my ($class, %args) = @_; #################### Start of changes #################### my $obj1 = $class->PClass1::new(%args); my $obj2 = $class->PClass2::new(%args); $this = $class->PClass1::new(%args); my $this = {( %{$obj1}, %{$obj2} )}; bless $this, $class; #################### End of changes #################### return $this; }