Previous Page Next Page

14.4. Inheritance

Inheritance means that a new class can inherit methods from an existing class. The new class can then add to or modify existing code in order to customize the class without having to reinvent what has already been done. The principle is that a class may be subdivided into a number of subclasses that all share common features, but each subclass may provide its own additional features, refining what it borrows to a more specific functionality. The idea of this kind of organization is not new. You may have seen it in a biology class when learning about the plant and animal kingdoms and the breakdown of each phylum, kingdom, class, order, family, species, and variety or in procedural programs with the use of functions to combine the common elements of a program into specific tasks.

In object-oriented programming, once a class has been written and debugged, it can be stored in a library and reused by other programmers. The programmer can then add features and capabilities to the existing class without rewriting the whole thing. This is done through inheritance; that is, by deriving a new class from an already existing class. The reuse of software and the increased use of library classes where all this software is stored and organized have contributed to the wide popularity of OOP languages. Let's see how Perl implements inheritance.

14.4.1. The @ISA Array and Calling Methods

The classes (packages) listed in the @ISA array are the parent, or base, classes of the current class. This is how Perl implements inheritance. The @ISA array contains a list of packages (classes) where Perl will search for a method if it can't find it in the current package (class). If the method still isn't found, then Perl searches for an AUTOLOAD function and calls that method instead. And if that isn't found, then Perl searches for the last time in a special predefined package called UNIVERSAL. The UNIVERSAL class is a global base class for all packages, the highest class in the hierarchy of classes.

The @ISA array is not searched in a call to a normal subroutine but in a call to a subroutine if it is called with the method invocation syntax.

Example 14.18.

   #!/bin/perl
   # Example of attempting inheritance without updating
   # the @ISA array
1  { package Grandpa;
2     $name = "Gramps";
3     sub greetme {
        print "Hi $Child::name I'm your $name from package Grandpa.\n";
      }
   }
4  { package Parent;
      # This package is empty
   }
5  { package Child;
6     $name = "Baby";
7     print "Hi I'm $name in the Child Package here.\n";
8     Parent->greetme();    # Use method invocation syntax
   }

(Output)
7  Hi I'm Baby in the Child Package here.
8  Can't locate object method "greetme" via package "Parent" at inher2 line 23.

					  

Explanation

1The package Grandpa is declared.
2The scalar $name is assigned Gramps in package Grandpa.
3The subroutine greetme is defined and when called, the print statement will be executed. $Child::name refers to the scalar $name in the Child package.
4The package Parent is declared. It is empty.
5The package Child is declared. This package will try to call a method from another package. Although objects and methods aren't being used here, the purpose of this example is to show you what happens if you try to inherit a method from a class that this package doesn't know about.
8Perl can't find the method greetme in package Parent and prints the error message.


Example 14.19.

    #!/bin/perl
    # Example of attempting inheritance by updating the @ISA array
1   { package Grandpa;
       $name = "Gramps";
2      sub greetme {
          print "Hi $Child::name I'm your $name from package Grandpa.\n";
       }
    }

3   { package Parent;
4      @ISA=qw(Grandpa);  # Grandpa is a package in the @ISA array.
                          # This package is empty.
    }

5   { package Child;
       $name = "Baby";
6      print "Hi I'm $name in the Child Package here.\n";
7      Parent->greetme();    # Parent::greetme() will fail
    }

(Output)
6   Hi I'm Baby in the Child Package here.
7   Hi Baby I'm your Gramps from package Grandpa.

Explanation

  1. The package Grandpa is declared.

  2. The subroutine greetme is defined and, when called, the print statement will be executed. $Child::name refers to the scalar $name in the Child package.

  3. The Parent package is declared.

  4. The @ISA array is assigned the name of the package Grandpa. Now if a method is called from this Child package and Perl can't find it, it will try the Grandpa package listed in the @ISA array. If you try to call a normal subroutine without method invocation, Perl won't consult the @ISA array, because it uses the @ISA array only when methods are being called. Even though the subroutines used here are not technically methods, by calling greetme as a class method, Perl will search the @ISA array.

  5. The Child package is declared.

  6. This line will be printed from the Child package.

  7. The class method greetme is called in the Parent package. The @ISA array tells Perl to look in the Grandpa package if the method isn't in the Parent package.

14.4.2. $AUTOLOAD, sub AUTOLOAD, and UNIVERSAL

If a subroutine (or method) cannot be found in the current package or in the @ISA array, the AUTOLOAD function will be called. The $AUTOLOAD variable is assigned the name of the missing subroutine if it is used with the AUTOLOAD function. Arguments passed to the undefined subroutine are stored in the AUTOLOAD subroutine's @_ array. If you assign a function name to the $AUTOLOAD variable, that subroutine will be called if the AUTOLOAD subroutine is provided in place of the missing subroutine. If the $AUTOLOAD variable is used with the AUTOLOAD subroutine, either the method or regular subroutine syntax can be used. If all fails and Perl still can't find the subroutine, a final package (class) called UNIVERSAL is searched for the missing method. The UNIVERSAL method contains three methods that all classes inherit. They are isa(), can(), and VERSION(). (See Table 14.2.)

Table 14.2. UNIVERSAL Methods
MethodWhat It DoesExample
isaReturns true if one package inherits from another.Salesman–>isa("Employee");
canReturns true if a package or any of its base classes contain a specified method.Salesman–>can("get_data");
VERSIONUsed to check that the correct modules are loaded for that version number. In the example, Perl calls the UNIVERSAL method Salesman–>VERSION(6.1).package Salesman; use$VERSION=6.1;


Example 14.20.

     #!/bin/perl
1    { package Grandpa;
       $name = "Gramps";
       sub greetme {
2       print "Hi $Child::name I'm your $name from package Grandpa.\n";
       }
     }

3    { package Parent;
4      sub AUTOLOAD{
5       print "$_[0]: $_[1] and $_[2]\n";
6       print "You know us after all!\n";
7       print "The unheard of subroutine is called $AUTOLOAD.\n"
       }
     }
8    { package Child;
       $name = "Baby";
9      $AUTOLOAD=Grandpa->greetme();
10     print "Hi I'm $name in the Child Package here.\n";
11     Parent->unknown("Mom", "Dad");   # Undefined subroutine
     }

(Output)
2   Hi Baby I'm your Gramps from package Grandpa.
10  Hi I'm Baby in the Child Package here.
5   Parent: Mom and Dad
6   You know us after all!
7   The unheard of subroutine is called Parent::unknown.

					  

Explanation

  1. The package Grandpa is declared. It contains one subroutine.

  2. This line is printed from the Grandpa package.

  3. The package Parent is declared. It contains an AUTOLOAD subroutine. An undefined subroutine is called on line 11. It has two arguments, Mom and Dad. If Perl can't find this subroutine in the Child package, it will look in the @ISA array, and if it is not there, Perl will look for an AUTOLOAD function.

  4. The subroutine AUTOLOAD is defined.

  5. Since this function was called as a class method, the first argument stored in the @_ array is the name of the class. The remaining arguments are Mom and Dad.

  6. This line is printed to show that we got here.

  7. The $AUTOLOAD variable contains the name of the class and the unnamed subroutine.

  8. The package Child is declared.

  9. If the scalar variable $AUTOLOAD is assigned the name of a subroutine, Perl will automatically call that subroutine.

  10. This line is printed to show in what order the lines are executed.

  11. The Child package wants to access a method in the Parent package. The Parent package does not contain a method or subroutine called unknown. It does, on the other hand, contain an AUTOLOAD subroutine that will be executed because this subroutine can't be found.

Example 14.21.

    #!/bin/perl
1   { package Grandpa;
      $name = "Gramps";
2     sub greetme {
         print "Hi $Child::name I'm your $name from package
             Grandpa.\n";
      }
    }
3   { package Parent;
       # This package is empty
    }
4   { package Child;
    $name = "Baby";
5   print "Hi I'm $name in the Child Package here.\n";
6   Parent->greetme();
    }

7   package UNIVERSAL;
8   sub AUTOLOAD {
9      print "The UNIVERSAL lookup package.\n";
10     Grandpa->greetme();
    }

(Output)
2   Hi I'm Baby in the Child Package here.
9   The UNIVERSAL lookup package.
5   Hi Baby I'm your Gramps from package Grandpa.

					  

Explanation

  1. The package Grandpa is declared.

  2. The subroutine greetme is defined in this package.

  3. The package Parent is declared. It is empty.

  4. The package Child is declared.

  5. This line is printed to show the flow of execution in the program.

  6. The greetme subroutine is called as one of the Parent package methods.

  7. Since the method could not be found in its own class or in the @ISA array, and an AUTOLOAD function is not supplied in the Parent package, Perl looks for package UNIVERSAL as a last resort. Here the subroutine AUTOLOAD calls greetme.

14.4.3. Derived Classes

As already discussed, inheritance is when one class can inherit methods from an existing class. The existing class is called the base, or parent, class, and the new class that inherits it is called the derived, or child, class. The base class has capabilities that all its derived classes inherit, and the derived class can then go beyond those capabilities. If a derived class inherits from one base class, it is called single inheritance. For example, single inheritance in real life might be that a child inherits his ability to draw from his father. If a derived class inherits from more than one base class, this is called multiple inheritance. To continue the analogy, the child inherits his ability to draw from his father and his ability to sing from his mother. In Perl, the derived class inherits methods from its base class (package) and can add and modify these methods when necessary.

The classes are inherited by putting them in the @ISA array. The methods to be exported to other modules can be specified in either the @EXPORTER or the @EXPORTER_OK arrays. The data itself is inherited by referencing keys and values in the anonymous hash where the data was initially assigned. These variables are called instance variables and are defined in the constructor method.

In Chapter 12, we looked at modules from the Perl standard library and modules you could create yourself. In order to include a module or pragma into your program, the use function was called with the module name (minus the .pm extension). The module had the capability to export symbols to other packages that might need to use the module. A special module called Exporter.pm handled the details for exporting and importing symbols between modules. This module also needs to be included in the @ISA array. If a module functions as a class, then its methods can be called without explicitly listing them in the @EXPORT array. Note in the following examples, the class methods and the instance methods are not exported.

Figure 14.4. Deriving classes from a base class.


The following examples demonstrate inheritance. Example 14.22 is the user of the Salesman.pm class. The user program need not make any reference to the base class, Employee.pm (see Example 14.23). The Salesman.pm class is derived from Employee.pm. The Salesman.pm class "uses" the Employee.pm class.

Example 14.22.

# The Driver (user) Program
1   use Salesman;
2   use strict;
    use warnings;
    # Create two salesman objects
    print "Entering data for the first salesman.\n";
3   my $salesguy1=Salesman->new;
4   $salesguy1->set_data;
5   print "\nEntering data for the second salesman.\n";

6   my $salesguy2=Salesman->new;
7   $salesguy2->set_data;

8   print "\nHere are the statistics for the first salesman.\n";
9   $salesguy1->get_data;
10  print "\nHere are the statistics for the second salesman.\n";
11  $salesguy2->get_data;

(Output)
    The salesman is an employee.
    The salesman can display its properties.
    Entering data for the first salesman.
    Enter the name of the employee. Russ Savage
    Enter the address of Russ Savage. 12 Main St., Boston, MA
    Enter the monthly base pay for Russ Savage. 2200
    Before blessing package is: Employee
    After blessing package is: Salesman
    Enter Russ Savage's commission for this month. 1200
    Enter Russ Savage's bonuses for this month. 500.50
    Enter Russ Savage's sales region. northeast

5   Entering data for the second salesman.
    Enter the name of the employee. Jody Rodgers
    Enter the address of Jody Rodgers. 2200 Broadway Ave, Chico, CA
    Enter the monthly base pay for Jody Rodgers. 34500
    Before blessing package is: Employee
    After blessing package is: Salesman
    Enter Jody Rodgers's commission for this month. 2300
    Enter Jody Rodgers's bonuses for this month. 1400
    Enter Jody Rodgers's sales region. northwest

8   Here are the statistics for the first salesman.
    Name = Russ Savage.
    Bonuses = 500.50.
    Commission = 1200.
    BasePay = 2200.
    Address = 12 Main St., Boston, MA.
    PayCheck = 3900.5.
    Region = northeast.


10  Here are the statistics for the second salesman.
    Name = Jody Rodgers.
    Bonuses = 1400.
    Commission = 2300.
    BasePay = 34500.
    Address = 2200 Broadway Ave, Chico, CA.
    PayCheck = 38200.
    Region = northwest.

					  

Explanation

1This use directive loads the Salesman module into this package, main. The program that contains the user interface is often called the driver program. It will be using the Salesman module to create a new salesman employee. Even though the Salesman class was derived from the Employee class, this program doesn't have to know that. All this program needs to do is call the Salesman constructor with the correct arguments (if any) and ask the user for input.
2The strict and warnings pragmas are turned on to help keep the program from using unsafe constructs and from making compile or runtime errors.
3The Salesman class constructor is called and returns a reference to a Salesman object, $salesguy1.
4The set_data method is called. The user is asked for input for the first salesman. This method is called from Salesman.pm.
6The constructor method for the Salesman module is called. A reference to the new Salesman object is returned and assigned to $salesguy2.
7The set_data method is called for the second salesman. This method is called from Salesman.pm.
9Inheritance is used here. The get_data method is called, but it is not implemented in the Salesman module. Perl searches the @ISA array in Salesman.pm and goes to the base class listed there, Employee. Since the get_data method is there, it will be called. The statistics for the first salesman are displayed.
11The get_data method is called for the second salesman.


 

Example 14.23.

    # Module Employee.pm
    # The Base Class
1   package Employee;
2   use strict;
3   use warnings;
    # Constructor method
4   sub new {
5      my $class = shift;
6      my $self = {_Name=>undef,
                   _Address=>undef,
                   _BasePay=>undef,
                  };
7      return bless($self, $class);
    }

    # Instance/access methods
8   sub set_data{
9      my $self=shift;
10        print "Enter the name of the employee. ";
11        chomp($self->{_Name}=<STDIN>);
          print "Enter the address of $self->{_Name}. ";
          chomp($self->{_Address}=<STDIN>);
          print "Enter the monthly base pay for $self->{_Name}. ";
          chomp($self->{_BasePay}=<STDIN>);
       }
12 sub get_data{
13    my $self=shift;
14    my ($key,$value);
15    print "Name = $self->{_Name}.\n";
16    while(($key,$value)=each(%$self)){
17       $key =~ s/_//;
18       print "$key = $value.\n" unless $key eq "Name";
      }
      print "\n";
   }
   1;

					  

Explanation

  1. The package is declared with the same name as the file, Employee.pm, minus the .pm extension. This is the base class. All employees have some common characteristics. In this example, they all have a name, an address, and a paycheck.

  2. The strict pragma will do strict error checking; in other words, restrict unsafe constructs, such as the use of global variables, barewords, etc.

  3. The warnings pragma will send warnings for probable compile or runtime errors.

  4. The Employee constructor method is defined. It is called new by convention.

  5. The name of the class will be shifted from the @_ array. This is a class method because it acts on behalf of the class and does not require an instance of the object.

  6. An anonymous hash will be assigned the attributes/properties for the object as key/value pairs. The values are undefined, to be assigned later. A reference to the hash is returned and assigned to $self. (The leading underscore on the keys is a convention used to indicate that this is private data for the object.)

  7. The object referenced by $self will be blessed into this class, Employee, and a reference to it will be returned to the caller.

  8. The subroutine set_data is an access method for the Employee class. When called, it will be used to assign data to the object; that is, add values to the keys in the anonymous hash.

  9. A reference to the object is shifted from the @_ array and assigned to $self.

  10. The user of the module is asked for input.

  11. The reference $self is used to assign values to the keys _Name, _Address, _BasePay.

  12. This access method is used to retrieve and display the object's data.

  13. A reference to the object is shifted from the @_ array and assigned to $self.

  14. Two lexical variables are declared.

  15. Because hash values are pulled in random order, this line guarantees that the name of the employee is displayed first.

  16. The while loop is entered, and the each function will extract the key/value pairs from the object by using the reference to the object ($%self).

  17. The leading underscore is removed from the key.

  18. The rest of the properties for the object are displayed.

Example 14.24.

    # The Derived Class
1   package Salesman;
2   use strict;
    use warnings;
3   BEGIN{unshift(@INC, "./Baseclass");};
4   our @ISA=qw( Employee);
5   use Employee;
6   print "The salesman is an employee.\n"
           if Salesman->isa('Employee');
7   print "The salesman can display its properties.\n"
           if Salesman->can('get_data');
8   sub new {        # Constructor for Salesman
9      my ($class)= shift;
10     my $emp = new Employee;
11     $emp->set_data;
12     print "Before blessing package is: ", ref($emp), "\n";
       bless($emp, $class);
13     print "After blessing package is: ", ref($emp), "\n";
       return $emp;
    }
14  sub set_data{
       my $self=shift;
15     my $calc_ptr = sub{ my($base, $comm, $bonus)=@_;
                       return $base+$comm+$bonus; };
16     print "Enter $self->{_Name}'s commission for this month. ";
       chomp($self->{_Commission}=<STDIN>);
       print "Enter $self->{_Name}'s bonuses for this month. ";
       chomp($self->{_Bonuses}=<STDIN>);
       print "Enter $self->{_Name}'s sales region. ";
       chomp($self->{_Region}=<STDIN>);
17     $self->{_PayCheck}=&$calc_ptr( $self->{_BasePay},
                                       $self->{_Commission},
                                       $self->{_Bonuses}
                                     );
    }
    1;

					  

Explanation

  1. The package (class) Salesman is declared.

  2. The strict and warnings pragmas are loaded.

  3. The BEGIN block is used to make sure the @INC array is updated at compile time so it will be available in the search for the base classes. The Employee.pm module is located in a subdirectory called Baseclass.

  4. The @ISA array contains the names of packages that will be used by this package. The Employee module is the base class needed by this Salesman module. The our function makes the @ISA array a lexical, global array. Without our, the strict pragma causes the compiler to abort the script because global variables are not allowed (unless you fully qualify their names with the package name and two colons).

  5. The use function causes the Employee module to be loaded into the program.

  6. All packages/classes inherit from the superclass called UNIVERSAL, which provides the isa method The isa method returns true if the Salesman module inherits from the Employee module.

  7. All packages/classes also inherit from the super class UNIVERSAL, which provides the can method. The can method returns true if the Salesman module or any of its parent classes contain a method called get_data, and undef if not.

  8. The Salesman class defines a constructor method called new.

  9. Arguments passed in are taken from the @_. The name of the class is assigned to $class.

  10. The constructor new for the Employee base class is called. A reference to the object $emp is returned.

  11. The Salesman class constructor calls set_data to add properties to the object.

  12. Before the blessing, the ref function returns the name of the class (package) the object belongs to, the Employee base class. The object, with its new properties, is now blessed into the Salesman class.

  13. After the blessing, the ref function returns the name of the class where the object was blessed, Salesman. A blessed reference to the object is returned to the caller.

  14. The instance method set_data is defined for the Salesman class.

  15. An anonymous subroutine is created to calculate the paycheck; a reference is returned. The subroutine should not be called by a user of the class. Only the class should be able to calculate the paycheck.

  16. New properties are added to the Employee class.

  17. The function to calculate the paycheck is called.

 

14.4.4. Multiple Inheritance

When a class inherits methods from more than one base, or parent, class, it is called multiple inheritance. In Perl, multiple inheritance is accomplished by adding more than one class to the @ISA array.

package  Child;
@ISA = qw (Mother Father Teacher);

The search is depth-first, meaning that Perl will search for classes in Mother and the hierarchy of classes it descends from, then Father and the hierarchy of classes it descends from, and finally Teacher and all its ancestors.

14.4.5. Overriding a Parent Method

There are times when two classes may have a method with the same name. If a derived class has a method with the same name as the base class, its method will take precedence over the base method. To override the method in the derived class so you can access the method in the base class, the name of the method must be fully qualified with the class name and two colons.

Example 14.25.

1   package Employee;  # Base class
    use strict;
    use warnings;
    sub new {          # Employee's constructor is defined
       my $class = shift;
       my %params = @_;
       my $self = { Name=>$params{"Name"},
                    Salary=>$params{"Salary"},
                  };
       bless ($self, $class);
       }
2   sub display {       # Instance method
       my $self = shift;
       foreach my $key ( @_){
3         print "$key: $self->{$key}\n";
       }
4      print "The class using this display method is ",
            ref($self),"\n";
    }
    1;
---------------------------------------------------------------------
5   package Salesman;  # Derived class
    use strict;
    use warnings;
    use Employee;
6   our @ISA=qw (Exporter Employee);
7   sub new {          # Constructor in derived Salesman class
       my $class = shift;
       my (%params) = @_;
       my $self = new Employee(%params);  # Call constructor
                                          # in base class
       $self->{Commission} = $params{Commission};
       bless ( $self, $class );     # Rebless the object into
                                    # the derived class
    }
    sub set_Salary {
       my $self = shift;
       $self->{Salary}=$self->{Salary} + $self->{Commission};
    }
8   sub display{        # Override method in Employee class
       my $self = shift;
       my @args = @_;
9      print "Stats for the Salesman\n";
       print "-" x 25, "\n";
10     $self->Employee::display(@args);  # Access to the
                                         # overridden method
    }
    1;
    -----------------------------------------
    # User or Driver Program
    #!/bin/perl
11  use Salesman;
    use strict;
    use warnings;
12  my $emp = new Salesman ( "Name", "Tom Savage",
                             "Salary", 50000,   # Call to constructor
                             "Commission", 1500,
                            );
    $emp->set_Salary;  # Call to the access method
13  $emp->display( "Name" , "Salary", "Commission");
                       # Call Salesman's display method

(Output)
9   Stats for the Salesman
    -------------------------
    Name: Tom Savage
    Salary: 51500
    The class using this display method is Salesman

					  

Explanation

  1. The class Employee is declared. It contains a constructor method called new and an instance method called display.

  2. The display access method is defined for the Employee class.

  3. The attributes for the employee are displayed.

  4. The ref function returns the name of the class of a blessed object.

  5. The Salesman class is declared. It will inherit from the Employee class and is called a derived class.

  6. The @ISA array includes the names of the classes it needs: the Exporter class and the base class, Employee.

  7. This is the Saleman's constructor.

  8. This display method takes precedence here in the derived class because it belongs to class Salesman. It is called in the driver program passing a reference to a Salesman object.

  9. The printout is coming from the derived class (Salesman) subroutine, display.

  10. By qualifying the name of the method to be of class Employee, this display method will override the current display method in package Salesman.

  11. This is the driver program. It uses the Salesman module.

  12. A new Salesman object is created, using the indirect method to call the constructor.

  13. The display method is called. Since there is a display subroutine in the Salesman class, it is the one that will be called.

 

Previous Page Next Page