Your class's constructor method overrides the constructor of its parent class. You want your constructor to invoke the parent class's constructor.
Learn about the special pseudoclass, SUPER.
sub meth { my $self = shift; $self->SUPER::meth( ); }
In languages like C++ where constructors don't actually allocate memory but just initialize the object, all base class constructors are automatically invoked for you. In languages like Java and Perl, you have to invoke them yourself.
To invoke a method in a particular class, the notation $self->SUPER::meth( ) is used. This is an extension of the regular notation that means to begin searching for a method in a particular class. It is valid only from within an overridden method. Here's a comparison of styles:
$self->meth( ); # Call wherever first meth is found $self->Where::meth( ); # Start looking in package "Where" $self->SUPER::meth( ); # Call overridden version
Simple users of the class should probably restrict themselves to the first line in the previous example. The second is possible, but not suggested for this situation, because we have the special notation shown in the third line, which only works within the overridden method.
An overriding constructor should invoke its SUPER's constructor to allocate and bless the object, limiting itself to instantiating any data fields needed. It makes sense here to separate the object allocation code from the object initialization code for reasons that will become clear a couple paragraphs from now. We'll name it with a leading underscore, a convention indicating a nominally private method. Think of it as a "Do Not Disturb" sign.
sub new { my $classname = shift; # What class are we constructing? my $self = $classname->SUPER::new(@_); $self->_init(@_); return $self; # And give it back } sub _init { my $self = shift; $self->{START} = time( ); # init data fields $self->{AGE} = 0; $self->{EXTRA} = { @_ }; # anything extra }
Both SUPER::new and _init are invoked with any remaining arguments. That way the user might pass other field initializers in, as in:
$obj = Widget->new( haircolor => red, freckles => 121 );
Whether you store these user parameters in their own extra hash is up to you.
Note that SUPER works only on the first overridden method. If your @ISA array has several classes, there could be several. A manual traversal of @ISA is possible, but seldom worth the hassle.
my $self = bless { }, $class; for my $class (@ISA) { my $meth = $class . "::_init"; $self->$meth(@_) if $class->can("_init"); }
This fragile code assumes that all superclasses initialize their objects with _init instead of initializing in the constructor. It also assumes that a hash reference is used for the underlying object.
For a slightly more general approach to accessing all overridden methods, save the return value from the can( ) method, which is the code reference to the subroutine that would be invoked through normal method invocation. Then use that reference for indirect method invocation.
sub some_method { my $self = shift; my %seen; print "some_method($self): checking all ancestors\n"; for my $parent (our @ISA) { if (my $code = $parent->can("some_method")) { $self->$code(@_) unless $seen{$code}++; } } }
To avoid calling the same subroutine more than once, the %seen hash keeps track of which subroutines have been called. This could happen if several parent classes shared a common ancestor.
Methods that would trigger an AUTOLOAD will not be accurately reported unless that package has declared (but not defined) the subroutines it wishes to have autoloaded.
The discussion on the SUPER class in perltoot(1) and perlobj(1), and in the section on "Method Invocation" in Chapter 12 of Programming Perl
Copyright © 2003 O'Reilly & Associates. All rights reserved.