Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call method in base class in Perl

Tags:

perl

#child.pm

#!/usr/bin/perl
package child1;
use strict;
use warnings;
use Exporter;
use parent;
my @ISA=qw(cal Exporter);
sub new{
        my $class=shift;
        my $ref=cal->new();
        bless ($ref,$class);
        return $ref;
        }
sub add{
        my $ref=shift;
        print "This is from child class";
        my($a,$b)=@_;
        return ($a+$b); 
        }

##parent.pm

#!/usr/bin/perl
package cal;
use strict;
use warnings;
use Exporter;
my @EXPORT=qw(add);
my @ISA=qw(Exporter EXPORT);
sub new{
        my $class=shift;
        my $ref=[];
        bless ($ref,$class);
        return $ref;
        }

sub add{
        my $ref=shift;
        my $a=shift;
        my $b=shift;
        return ($a+$b);
        }
1;

#test.pl

#!/usr/bin/perl
use strict;
use warnings;
use Exporter;
use child;
my @ISA=qw(child1 Exporter);
my $obj=new child1();
my $sum=$obj->add(1,2);
print "$sum=sum";

I am getting the error Can't locate object method "add" via package "child1" at ./test.pl line 8. I want to access the base class add method and I am getting this above error

please clarify..

like image 440
user2560452 Avatar asked Jul 24 '13 11:07

user2560452


Video Answer


3 Answers

The main culprit here is my @ISA. For inheritance to work, you have to use the package @ISA (declare it with our).

However, there are some issues in your code beyond that:

  1. Please use parent 'cal' instead of manipulating @ISA yourself.
  2. Object-oriented modules have little reason to use Exporter.
  3. The child1's new can be written without reblessing, because the parent's new is inherited. The inherited new is written in a way that already supports inheritance.
  4. Don't give your modules lower-case names, these are reserved for “pragmas”. The parent module already exists, and I used it in my 1st point.
like image 105
amon Avatar answered Oct 23 '22 08:10

amon


@ISA must be a public package variable, not a private lexical (my). Same for @EXPORT. Change my to our on all those declarations.

Even better, depending on the version of perl you have, simplify you life with either the parent or base pragma to load superclasses and to set up the class relationships.

With respect to style, you will avoid considerable confusion if you make the paths to the files that contains your modules’ code match their package names. You would do well to heed a well-established convention described in the perlmod documentation.

Module names are also capitalized unless they're functioning as pragmas; pragmas are in effect compiler directives, and are sometimes called “pragmatic modules” (or even “pragmata” if you're a classicist).

The Cal module uses an internal _initialize method as described in the perlobj documentation to facilitate inheritance of the constructor.

See below for a complete working example.

Cal.pm

package Cal;

use strict;
use warnings;

sub new {
  my $class=shift;
  my $self=[];
  bless ($self,$class);
  $self->_initialize();
  return $self;
}

sub _initialize {}

sub add {
  my $ref=shift;
  my $a=shift;
  my $b=shift;
  print "This is from parent class\n";
  return ($a+$b);
}

1;

Child1.pm

package Child1;

use warnings;
use strict;

use v5.10.1;  # when parent was added to the core
use parent "Cal";

# if you have an older perl, use base instead of parent
# use base "Cal";

sub _initialize {
  my $self=shift;
  push @$self, "I am a " . ref($self) . "!";
}

sub add{
  my $self=shift;
  my($a,$b)=@_;
  print "This is from child class\n";
  return ($a+$b);
}

1;

test.pl

#!/usr/bin/perl

use strict;
use warnings;

use Child1;

my $obj=Child1->new();

my $sum1=$obj->add(1,2);
print "$sum1=sum1\n";

# call the add method in Cal
my $sum2=$obj->Cal::add(1,2);
print "$sum2=sum2\n";

# call add as a class method of Cal, which
# happens to work in this case because Cal::add
# does not use the instance passed to it
my $sum3=Cal->add(1,2);
print "$sum3=sum3\n";

Output:

This is from child class
3=sum1
This is from parent class
3=sum2
This is from parent class
3=sum3
like image 38
Greg Bacon Avatar answered Oct 23 '22 09:10

Greg Bacon


The .pm modules do not need, and likely do not want, the #!/usr/bin/perl lines. This is only for programs intended to be executed from the command line, like your .pl module. While you may 'perl -cw' your .pm modules, or do other command line debugging with them, such is not normal "production" use.

And .pl modules should not have @ISA, or other "our" declarations found in packages nor any exporter related things.

As said before, change "my"s for package stuff to "our"s. The "my" hides things to outsiders as if the statements were never there.

In the "cal" class, do you want something like the following? I favor SUPER as it really shows what is going on and is much more generic.

package child1;
use Exporter;
our @ISA=qw(cal Exporter);

sub new{
        my $class=shift;
        my $ref=$class->SUPER::new();
        return $ref;
        }
}

One final point: you may need a "\n" on the final print statement. Without it the buffer may not flush correctly on exit in some environments so you will never see the output.

like image 6
Gilbert Avatar answered Oct 23 '22 10:10

Gilbert