Inheritance

The bless function gives more information to a reference. It makes the reference be of a type: Student in this case. This has several uses in Perl, as we shall see. Using public methods to access private data is not the only benefit of the object-oriented approach. Another important principle, inheritance, is the cornerstone of object orientation.

Inheritance is one of the principal ways of implementing code reuse. The following are examples of inheritance relationships.

  • A Directory is a type of File.

  • A Manager is a type of Employee.

  • A Car is a type of MovingVehicle.

  • A Circle is a type of Shape.

Sometimes inheritance is characterized as the is-a relationship. In the File–Directory relationship, we say that a Directory is-a File. Likewise, a Circle is-a Shape. Other common terminology is that File is the superclass of Directory. Also, Shape is the superclass of Circle. Likewise, Circle is a subclass of Shape and Directory is a subclass of File.

If we already have a File class, we should not have to build the Directory class from the beginning. Since a Directory is a File, any Directory object should be able to reuse (without rewriting) all of the File methods.

To illustrate inheritance, suppose that we have a special kind of student—a GradStudent. For simplicity, let's say a GradStudent is a Student with a salary. The GradStudent class needs to specify that it is a derived class of Student. This is done by using the special @ISA array, as you will see below. All methods defined in the Student package can be reused by any GradStudent object.

GradStudent must implement a constructor and possibly a destructor, as well as any incremental behavior that specializes a GradStudent, such as getsalary and setsalary.

Using SUPER in Inheritance

The constructor for the subclass typically needs to call the constructor in its superclass. This is accomplished by using the keyword SUPER. Here is the constructor for a GradStudent. Notice how SUPER is used in the new method in the file GradStudent.pm. See the folder GradStudent.


% type GradStudent.pm
#
#   GradStudent.pm
#
package GradStudent;
use Student;
#
#   The next line tells Perl that
#   GradStudent is derived from Student
#
@ISA=qw(Student);
#
#   GradStudent's new
#
sub new
{
    my $pkg = shift;
    my ($name, $major, $salary, @subjs) = @_;
#
#    Call new in the SUPER (Student) class
#    In the call, $pkg == GradStudent
#
    my $obj=$pkg->SUPER::new($name, $major, @subjs);
    $obj ->{'SALARY'} = $salary;
    $obj;
}
sub salary
{
    my($pkg) = shift;
    @_ ? $pkg ->{SALARY} = shift : $pkg ->{SALARY};
}
1;

When a GradStudent object is created, the data for it is passed to the constructor new in the same way that the Student new constructor was called when a Student was constructed. Then there is a call to the Student constructor. It is necessary for the GradStudent constructor to call the Student constructor in order to construct the Student portion of a GradStudent.

my $obj=$pkg->SUPER::new($name, $major, @subjs);

The line above calls the new method in the Student class in such a way that the first argument in the call is GradStudent. This is because GradStudent is the value of $pkg. When Student::new returns, the returned reference has been blessed as a GradStudent, not as a Student. Finally, the salary field is added to the reference and the reference is returned.

The line

@ISA=qw(Student);

tells Perl that the GradStudent class is a subclass of Student and thus any GradStudent object can freely reuse all Student methods. Here is a program that demonstrates the use of the GradStudent class. See the folder UseGradStudent.


% type UseGradStudent.pl
#
#   useGradStudent.pl
#
use Student;
use GradStudent;
$stu1 = new Student(Mike, Math, Alg, Calc, Trig);
print $stu1->getname(), "
";
print $stu1->getmajor(), "
";
$gs=new GradStudent(Dave, Math, 25000, Calc, Trig);
#
#   reuse Student functionality
#
print $gs->getname(), "
";
print $gs->getmajor(), "
";
#
#   a new method
#
print $gs->salary(), "
";

The methods getname() and getmajor() are implemented in the Student.pm file. Since a GradStudent is a Student (because of the @ISA array), these methods may be used on Student and GradStudent objects. Code reuse is a major benefit of inheritance. The salary() method is implemented only for a GradStudent.

Polymorphism

Consider a set of classes related through inheritance. The classic example is a set of classes derived from a geometric Shape class. Each class, say Circle, Square, and Triangle, would have its own area and perimeter methods. Each of these methods would have a class-specific implementation. The skeleton code for an application for such a scenario would be:

$circ1e1 = new Circle(5);         # create a Circle
$square1 = new Square(10);        # create a Square
print $square->area(),"
";       # area of Square
print $circle1->perimeter(),"
"; # perimeter of Circle

The capability of a language to differentiate among several methods, all of which have the same name in the same inheritance hierarchy, is called polymorphism. Polymorphism is implemented in Perl through the bless function. When an object is blessed, it is bound to a class. When a method is called upon this object, the chosen method comes from the class bound to the object.

Here is an example to illustrate polymorphism with respect to the Shapes hierarchy.

Although we will never have a Shape object, we need to create a Shape class in order to factor out some common methods and data that apply to all subclasses.

% type Shape.pm
#
#   Shape.pm
#
package Shape;
sub new
{
    my ($pkg, $val) = @_;
    my ($shref) = { value => $val };
    print "Creating a $pkg of size $val
";
    bless $shref, $pkg;
    return $shref;
}
sub getvalue
{
    my ($pkg) = @_;
    return $pkg -> {value};
}
1;
%

The new method of the Shape class will never be called directly. It will, however, be called by the new method of any Shape subclasses, such as Circle and Square. The getvalue() method will be used by all derived classes to retrieve parameter information, such as the radius for a circle or the side for a square.

Next, we show the Circle and Square classes.

% type Circle.pm
#
#   Circle.pm
#
package Circle;
@ISA = ('Shape'),
sub new
{
    my ($pkg, $rad) = @_;
    $pkg ->SUPER::new($rad);
}
sub perimeter
{
    my ( $pkg) = @_;
    return 2 * 3.14159 * $pkg -> {value};
}

sub area
{
    my ( $pkg) = @_;
    return 3.14159 * $pkg -> {value} ** 2;
}
sub type()
{
    "Circle";
}
1;
% type Square.pm
#
#   Square.pm
#
package Square;
@ISA = ('Shape'),
sub new
{
    my ($pkg, $rad) = @_;
    $pkg ->SUPER::new($rad);
}
sub perimeter
{
    my ( $pkg) = @_;
    return   4 * $pkg -> {value};
}
sub area
{
    my ( $pkg) = @_;
    return  $pkg -> {value} ** 2;
}
sub type
{
    "Square";
}
1;
%

The Circle and Square classes implement their own versions of area and perimeter but rely on the Shape class for a common version of getvalue(). Finally, here is a program that uses these classes. See the folder UseShapes.


% type useShapes.pl
#
#       useShapes.pl
#
use Shape;
use Circle;
use Square;
$sq1 = new Square(10);
$sq2 = new Square(20);
$c1  = new Circle(5);
$c2 =  new Circle(10);
push(@array, $c1, $c2, $sq1, $sq2);
foreach $s (@array)
{
    print "TYPE IS:	",   $s->type(), "
";
    print "PARAM IS:	",  $s->getvalue(), "
";
    print "AREA IS:	",   $s->area(), "
";
    print "CIRCUM IS:	", $s->perimeter(), "
";
    print "_________________________________
";
}
% perl useShapes.pl
Creating a Square of size 10
Creating a Square of size 20
Creating a Circle of size 5
Creating a Circle of size 10
TYPE IS:  Circle
PARAM IS: 5
AREA IS:  78.53975
CIRCUM IS:31.4159
_________________________________
TYPE IS:  Circle
PARAM IS: 10
AREA IS:  314.159
CIRCUM IS:62.8318
_________________________________
TYPE IS:  Square
PARAM IS: 10
AREA IS:  100
CIRCUM IS:40
_________________________________
TYPE IS:  Square
PARAM IS: 20
AREA IS:  400
CIRCUM IS:80
_________________________________
%

@array contains references to either Circle or Shape objects. When a method is invoked on these objects, Perl checks to see if the class to which this object is blessed contains this method. If it does, it is invoked. If it does not, then the superclass is checked. The superclass is known through the use of the @ISA array.

Methods whose behavior is invariant over specialization should belong to the Shape class and be used as a default implementation for subclasses. getvalue is one of these methods. Methods whose behavior varies on a class-specific basis should belong to the specific class. area(), perimeter(), and type() are a few of these methods.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.17.203.68