Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
 iakovlev.org 
 Languages
 С
 GNU С Library 
 Qt 
 STL 
 Threads 
 C++ 
 Samples 
 stanford.edu 
 ANSI C
 Libs
 LD
 Socket
 Pusher
 Pipes
 Encryption
 Plugin
 Inter-Process
 Errors
 Deep C Secrets
 C + UNIX
 Linked Lists / Trees
 Asm
 Perl
 Python
 Shell
 Erlang
 Go
 Rust
NEWS
Последние статьи :
  Rust 07.11   
  Go 25.12   
  EXT4 10.11   
  FS benchmark 15.09   
  Сетунь 23.07   
  Trees 25.06   
  Apache 03.02   
  SQL 30.07   
  JFS 10.06   
  B-trees 01.06   
 
TOP 20
 Trees...564 
 Go Web ...356 
 Python...179 
 Rubni-Corbet -> Глав...167 
 2.0-> Linux IP Networking...158 
 Steve Pate 3...148 
 Stein-MacEachern-> Час...143 
 Стивенс 9...133 
 Mike Perry...127 
 Daniel Bovet 2...127 
 Secure Programming for Li...124 
 Advanced Bash Scripting G...123 
 Rubni-Corbet -> Глав...122 
 Stevens-> Глава 4...121 
 Rubni-Corbet -> Глав...119 
 Stewens -> IPC 7...118 
 Stewens -> IPC 9...115 
 Ethreal 4...115 
 Rodriguez 6...111 
 Stevens-> Глава 23...110 
 
  01.12.2017 : 2356398 посещений 

iakovlev.org

OOP


Вы слышали о таких терминах, как "modules", packages", "classes", "references", "constructors" ...

#1: Ключем к пониманию OOP в Perl является концепция "references".

#2: "packages", "classes" и "modules" - суть синонимы (хотя это конечно не совсем так). Далее мы будем использовать слово "packages".

#3: "Methods" и "objects" - обьекты или сущности,которые находятся внутри пакетов. То же можно сказать про "constructors", "destructors" и "overrides".


В Perl ссылка-это указатель. Она позволяет программисту получать доступ к значению переменной, не используя обращение к имени переменной.

Пример:


#!/usr/bin/perl

# set variable
$me = "popeye";

# set reference
$ref = \$me;

# print values
print "The value of \$me is $me\n";
print "The value of \$ref is $ref\n";


In this case, we've first initialized a standard Perl scalar and then created a reference to it by prefixing it with a backslash[\]. Now, the reference and the variable itself are two different things - as you'll see when you run the script and get output that looks like this:


The value of $me is popeye
The value of $ref is SCALAR(0x80baa88)


Thus, the reference $ref is simply a pointer to an address in memory which stores the value of the variable $me. The word SCALAR that you see indicates the type of data, while the hexadecimal number following it is the actual memory address. Try memorizing it and see if you can say it backwards really fast.

Now, how about going full circle and using the reference to actually get the value of the variable and display it?


#!/usr/bin/perl

# set variable
$me = "popeye";

# set reference
$ref = \$me;

# print values
print "The value of \$ref is $ref\n";
print "The value of the referenced variable is $$ref\n";


And the output is:


The value of $ref is SCALAR(0x80baa88)
The value of the referenced variable is popeye


In this case, by placing a single $ before the variable containing the reference, you are able to get the original value of the reference (as opposed to some hexadecimal gibberish). Just so you know, this is referred to as "dereferencing" a variable. Geeks need new words for everything.


You can also reference and dereference other types of Perl constructs - the next example shows you how to do this with arrays and hashes.


#!/usr/bin/perl

# set array variable
@friends = ("Rachel", "Phoebe", "Monica", "Joey", "Chandler", "Ross");

# set hash
%animals = ('donald'=>'duck', 'mickey'=>'mouse', 'cheshire'=>'cat');

# set reference for array
$ref = \@friends;

# set reference for hash
$fer = \%animals;

# print values
print "The value of \$ref is $ref\n";
print "The value of \$fer is $fer\n";
print "\n";
print "The value of the first array element is $$ref[0]\n";
print "The value for the key \"mickey\" is $$fer{'mickey'}\n";


And the output is:


The value of $ref is ARRAY(0x80baa94)
The value of $fer is HASH(0x80bab18)

The value of the first array element is Rachel
The value for the key "mickey" is mouse


Note how the data type of the referenced variable is clearly visible when you print the reference.

Don't just restrict yourself to variables, either - you can easily create a reference to a Perl subroutine like this:


#!/usr/bin/perl

# set variable
$me = "popeye";

# subroutine
sub whoami {
print "My name is $me\n";
}

# reference to subroutine
$ref = \&whoami;

# print values
print "The value of \$ref is $ref\n";

# and run the subroutine via reference
&$ref;


And the output is:


The value of $ref is CODE(0x80baaac)
My name is popeye



Just so you know, Perl also allows you to combine two steps into one by creating a reference directly, without using the backslash operator. For example, you could create an array reference like this (as in the example on the previous page):


# set array variable
@friends = ("Rachel", "Phoebe", "Monica", "Joey", "Chandler", "Ross");

# set reference for array
$ref = \@friends;

# print values
print "The value of \$ref is $ref\n";


or like this


# set array reference
$arrayref = ["Rachel", "Phoebe", "Monica", "Joey", "Chandler", "Ross"];

# print values
print "The value of \$arrayref is $arrayref\n";


By enclosing the array elements in square braces, Perl allows you to create a reference directly (in a prime example of bad geek humour, this is known as an anonymous array, primarily because it doesn't have a name.) When you print the value of $arrayref, you'll see something like this:


The value of $arrayref is ARRAY(0x80b5670)


You can also create an "anonymous hash" by enclosing the key-value pairs in curly braces


$hashref = {'donald'=>'duck', 'mickey'=>'mouse', 'cheshire'=>'cat'};


and "anonymous subroutines" by using the "sub" keyword without a name after it.


$subref = sub {
print "My name is $me\n";
};



There's one important caveat when dealing with references, and it relates to copying them. Just as you can copy the value of one variable into another, Perl also allows you to copy references. The following example demonstrates this clearly.


#!/usr/bin/perl

# set variable
$icecream = "peach";

# set reference
$alpha = \$icecream;

# copy reference
$beta = $alpha;

# print state
print "BEFORE\n";
print "icecream = $icecream\n";
print "alpha(ref) = $alpha\n";
print "alpha(val) = $$alpha\n";
print "beta(ref) = $beta\n";
print "beta(val) = $$beta\n";


And the output is


BEFORE
icecream = peach
alpha(ref) = SCALAR(0x80baa88)
alpha(val) = peach
beta(ref) = SCALAR(0x80baa88)
beta(val) = peach


However, note what happens when you change the value of the copied reference.


#!/usr/bin/perl

# set variable
$icecream = "peach";

# set reference
$alpha = \$icecream;

# copy reference
$beta = $alpha;

# print state
print "BEFORE\n";
print "icecream = $icecream\n";
print "alpha(ref) = $alpha\n";
print "alpha(val) = $$alpha\n";
print "beta(ref) = $beta\n";
print "beta(val) = $$beta\n";

# change beta
$$beta = "raspberry";

# print state
print "AFTER\n";
print "icecream = $icecream\n";
print "alpha(ref) = $alpha\n";
print "alpha(val) = $$alpha\n";
print "beta(ref) = $beta\n";
print "beta(val) = $$beta\n";


The output now makes for interesting reading.


BEFORE
icecream = peach
alpha(ref) = SCALAR(0x80baa88)
alpha(val) = peach
beta(ref) = SCALAR(0x80baa88)
beta(val) = peach
AFTER
icecream = raspberry
alpha(ref) = SCALAR(0x80baa88)
alpha(val) = raspberry
beta(ref) = SCALAR(0x80baa88)
beta(val) = raspberry


The lesson here? Simple. When you copy variables, changing one has no effect on the other. But when you copy references, since a reference is a direct hook into memory, changing one of the copies affects the original value of the variable and also (obviously) the other copies of the reference.


Next up, packages. In Perl-lingo, a package can best be thought of as a self-contained unit of user-defined variables and subroutines, which can be re-used over and over again. In fact, this very reusability is the reason Perl programmers are so fond of packages, frequently using them to build "modules" which they then distribute to all and sundry.

Defining a package takes place via the "package" keyword, which is followed by the name of a package. The statement


package Sumthing;


would tell the Perl interpreter that the code following it belongs to the package named "Sumthing".

Once you've defined your package, you can add variable declarations and subroutine calls to it exactly as you would normally.


#!/usr/bin/perl

package Sumthing;

# subroutine
sub add {
$sum = $alpha+$beta;
print "Sum is $sum\n";
}

# variables
$alpha = 10;
$beta = 4;


In the example above, the package named "Sumthing" contains a couple of variables, and a function that adds them up and prints them out.

Typically, the scope of the package definition extends to the end of the file, or until another "package" keyword is encountered.

A quick aside on modules here: once you've got your package together, you can convert it to a module by saving it to a file called "Sumthing.pm" (the .pm extension signifies a Perl Module, which is nothing but a package or collection of packages designed to be reusable). All Perl module files end in the extension .pm, and Perl module names typically begin with a capital letter.


# Sumthing.pm - a Perl module which performs addition

package Sumthing;

# subroutine
sub add {
$sum = $alpha+$beta;
print "Sum is $sum\n";
}

# variables
$alpha = 10;
$beta = 4;

1;


Note the


1;


at the end of the module file - this is typically done so that a use() or require() function call to the module succeeds.

More on how to use modules later.


The important thing to remember here is that the variables and subroutines are private to a particular package, and cannot be accessed outside it. So, if you were to create another package named "Sumotherthing", as the following example demonstrates, "Sumotherthing" would not be able to access subroutines and variables from "Sumthing"...


#!/usr/bin/perl

package Sumthing;

# subroutine
sub add {
$sum = $alpha+$beta;
print "Sum is $sum\n";
}

# variables
$alpha = 10;
$beta = 4;

package Sumotherthing;

# variables
$alpha = 2;
$beta = 40;

# subroutine
sub multiply {
$product = $alpha*$beta;
print "Product is $product\n";
}

# print the value of alpha

# since no "package" statement has been encountered, this statement will only
# "see" the package Sumotherthing

print "The value of \$alpha is $alpha\n";


...unless it explicitly called variables and functions in "Sumthing" by preceding the variable/subroutine name with the package name.


#!/usr/bin/perl

package Sumthing;

# subroutine
sub add {
$sum = $alpha+$beta;
print "Sum is $sum\n";
}

# variables
$alpha = 10;
$beta = 4;

package Sumotherthing;

# variables
$alpha = 2;
$beta = 40;

# subroutine
sub multiply {
$product = $alpha*$beta;
print "Product is $product\n";
}

# print the value of alpha

# since no "package" statement has been encountered, this statement will only
# "see" the package Sumotherthing

print "The value of \$alpha is $alpha\n";

# now switch to the other package and print

package Sumthing;
print "The value of \$alpha is $alpha\n";

# you could also use the double-colon notation to access constructs from
# other packages

# this prints the value of "alpha" from Sumthing
print "The value of \$alpha from package #1 is " . $Sumthing::alpha . "\n";

# while this prints the value of "alpha" from Sumotherthing
print "The value of \$alpha from package #2 is " . $Sumotherthing::alpha . "\n";

# works for subroutines too!
# this runs the add() routine from Sumthing

&Sumthing::add();

# and this runs the multiply() routine from Sumotherthing
&Sumotherthing::multiply();


And the output is:


The value of $alpha is 2
The value of $alpha is 10
The value of $alpha from package #1 is 10
The value of $alpha from package #2 is 2
Sum is 14
Product is 80


Just so you know, packages aren't something to be afraid of. By default, all the Perl code you write resides within the domain of the uber-package, the one they call "main". The following snippet will demonstrate this:


#!/usr/bin/perl

$language="Francais";

print "Parlez-vous $main::language?\n";


In this case, since there is no mention of a specific package, the variable $language is created in the domain of the package "main".

Finally, the "package" keyword, by itself, indicates that subsequent variables will not be accepted by Perl unless they are explicitly preceded by a package name.


Finally, it's time to get down and play in the mud with a few "objects". In Perl, an "object" is simply a reference that belongs to a specific package. And the method used to associate a reference with a specific package is referred to as "blessing", because the function used to perform the association is the bless() function.

For example,


package Easterbunny;

sub new
{
my $this = {};
bless $this;
return $this;
}


In this case, the first line within the subroutine creates an anonymous hash reference (this was covered a few pages back). The next line bless()es this reference and associates it with the package Easterbunny and sends it back as a return value.

Now, take a minute to read this definition of a constructor from the Perl manual. It says that "... a constructor is merely a subroutine that returns a reference to something blessed into a class, generally the class that the subroutine is defined in..."

In other words, you just wrote your first constructor.

Obviously, the new() constructor, or subroutine, above can do a whole lot more than just bless() references. For example, you could have it spit out a few choice insults to the poor programmer who decided to invoke it, as in the following example.


package Easterbunny;

sub new
{
my $this = {};
print "Grow up. Get a life. You suck.\n";
bless $this;
return $this;
}



Finally, it's time to do something with the package you just created. If you haven't done it already, save the package from the last example to a file named "Easterbunny.pm" in your Perl library path with all the other .pm files (in case you don't know the location of those files, try checking the @INC variable). Remember that since this is now a module, you need to add the all-important


1;


to the end of the file. Then create a Perl script which looks like this:


#!/usr/bin/perl

use Easterbunny;

$bob = new Easterbunny;


The first line of the file looks for the Perl module "Easterbunny.pm" and reads it in for use.

The second line creates a new instance of Easterbunny by invoking the new() constructor, and assigns it to $bob.

You can also invoke the new() constructor in any of the following ways:


$bob = Easterbunny::new();

$bob = Easterbunny->new();


And the output will look something like this:


Grow up. Get a life. You suck.


Before we get into the nitty-gritty of object methods and properties, I want to take a minute to make sure that we're all clear on the basics. And I'm going to use an example I've used before to communicate the concept to those of you who may still not be too comfortable with it.

Take your car, the vehicle that transports you from place to place, and consider this, within the framework of OOP, as an "object". This object has certain basic properties - shape, size, colour - and certain basic functions - start, stop, accelerate and decelerate.

Now take it one step further. Every car can, in fact, be considered a subset of the class Automobile, which defines the basic characteristics and functions of every automobile on the planet. Once the class Automobile spawns a new car, or "object", its individual characteristics (color, shape) can be changed without affecting either the parent class or other spawned objects.

In Perl, a class is equivalent to a package - and the package might look something like this:


# this is Automobile.pm
# a Perl module to create new automobiles

package Automobile;

# constructor
sub new
{
my $this = {};
bless $this;
return $this;
}

# subroutine (aka "object method")
sub init
{
# code to initialize variables (aka "object properties")
# this won't stay empty for long - keep reading!
}

# a few other object methods
sub start
{
# some code
}

# a few other object methods
sub stop
{
# some code
}

sub accelerate
{
# some code
}

sub decelerate
{
# some code
}

# remember to end the module with this
1;


In order to use this, you simply need to instantiate a new object in your Perl script by calling the constructor, like this:


#!/usr/bin/perl

use Automobile;

# create objects
$his = new Automobile;
$hers = new Automobile;

# run a few object methods

# let's take this baby out for a spin
$his->start();

# well, hello there, pretty lady!
# care to join me?
$hers->start();

# this is fun!
$his->accelerate();
$hers->accelerate();

# was that a speed trap?
$his->decelerate();
$hers->decelerate();

# busted!
$his->stop();
$hers->stop();


You're already familiar with the method of creating a new object - the example above simply demonstrates the manner in which other methods can be applied to the object. These methods are nothing more than subroutines within the package definition.


Now let's toss something new into the mix, by adding a few object properties to the constructor.


# this is Automobile.pm
# a Perl module to create new automobiles

# constructor
sub new
{
my $this = {};

# object properties
$this->{colour} = undef;
$this->{make} = undef;
$this->{shape} = undef;

bless $this;
return $this;
}

# other subroutines


Once you've added the variables to the constructor, you also need a way to initialize them - which is where the init() subroutine comes in. Let's add a bit of code to that, shall we?


# this is Automobile.pm
# a Perl module to create new automobiles

# other subroutines

sub init
{
my $this = shift;
$this->{color} = shift;
$this->{make} = shift;
$this->{shape} = shift;
}

# other subroutines


And now let's modify the test script - I'll use the init() method to create two completely different Automobiles.


#!/usr/bin/perl

use Automobile;

# create objects
$his = new Automobile;
$his->init("black","Ferrari","cigar");

$hers = new Automobile;
$hers->init("silver","Porsche","torpedo");

# run a few object methods

# let's take this baby out for a spin
$his->start();

# and so on


This time around, once an object is created, the init() method sets up some default properties like shape, make and colour. (You're probably wondering what all the shift()-ing is about in the subroutines above - don't worry about it for the moment, I've explained it all on the next page.)

And finally, how about doing something with the properties sent to the init() method? Let's add one more method, which lets you brag about your new car (and demonstrate how object properties can be used, too!)


# this is Automobile.pm
# a Perl module to create new automobiles

# other subroutines

sub brag
{
my $this = shift;
print "Guess what? I've just got myself a brand-spanking-new $this->{color}
$this->{make}, shaped like a $this->{shape}. Sure, I'll take you for a ride
in it. Call me."
}

# other subroutines


And let's make a final modification to our test script:


#!/usr/bin/perl

use Automobile;

$his = new Automobile;
$his->init("yellow", "Lamborghini", "missile");
$his->brag():


And here's what you should see when you run it:


Guess what? I've just got myself a brand-spanking-new yellow Lamborghini, shaped like a missile. Sure, I'll take you for a ride in it. Call me.


And, as you'll see if you experiment a little, you can create as many Automobiles as you like, each with different properties, and the brag() method will display an appropriate message for each one. Ain't OOP cool?


I promised I'd explain about the numerous calls to shift() in the init() subroutine (for those of you who don't know, the shift() function removes the first element of an array). It's actually pretty simple, and has to do with the difference between calling a subroutine and calling a method on an object.

Let's suppose you were to call the subroutine


Automobile::init("silver")


In this case, the @_ argument list to the subroutine init() would look like this:


@_ = ("silver");


However, if you were to call the method


$his = new Automobile;
$his->init("silver");


the @_ argument list would store two items - an object reference and the argument itself, or


@_ = ($ref, "silver");


You need to use the shift() function to remove the reference from the argument list - which is why most object methods begin with


my $this = shift;



Now that you've (hopefully) understood the fundamental principles here, let's move on to something slightly more practical. This next package allows you to create different Clock objects, and initialize each one to a specific time zone. You could create a clock which displays local time, another which displays the time in New York, and a third which displays the time in London - all through the power of Perl objects. Let's take a look:


# Clock.pm
# a module to create a simple clock
# each Clock object is initialized with two offsets (hours and minutes)
# indicating the difference between GMT and local time

package Clock;

# constructor
sub new
{

my $self = {};

# define variables to store timezone offset from GMT, in hours and minutes,
# and city name
$self->{offsetSign} = undef;
$self->{offsetH} = undef;
$self->{offsetM} = undef;
$self->{city} = undef;

bless($self);
return $self;
}


# method to set the offset hour and minute wrt GMT
# this accepts an offset direction
# and two numerical parameters, hours and minutes.

sub set_offset
{

my $self = shift;

$self->{offsetSign} = shift;
$self->{offsetH} = shift;
$self->{offsetM} = shift;
$self->{city} = shift;

}

# method to display current time, given offsets

sub display
{

my $self = shift;

# use the gmtime() function, used to local convert time to GMT
# returns an array

@GMTTime = gmtime();

$seconds = @GMTTime[0];
$minutes = @GMTTime[1];
$hours = @GMTTime[2];

# calculate time
if($self->{offsetSign} eq '+')
{

        # city time is ahead of GMT
        $minutes += $self->{offsetM};

        if($minutes > 60)
        {
        $minutes -= 60;
        $hours++;
        }

        $hours += $self->{offsetH};

        if($hours >= 24)
        {
        $hours -= 24;
        }

}
else
{
        # city time is behind GMT

        $seconds = 60 - $seconds;
        $minutes -= $self->{offsetM};

        if($minutes < 0)
        {
        $minutes += 60;
        $hour--;
        }

        $hours -= $self->{offsetH};

        if($hours < 0)
        {
        $hours = 24 + $hours;
        }
}

# make it look pretty and display it
$self->{localTime} = $hours.":".$minutes.":".$seconds;
print "Local time in $self->{city} is $self->{localTime}\n";
}

1;


As you can see, we've got four variables: the name of the city, an indicator as to whether the city time is ahead of, or behind, Greenwich Mean Time, and the difference between the local time in that city and the standard GMT, in hours and minutes. Once these properties are made available to the package via the set_offset() method, the display() method takes over and performs some simple calculations to obtain the local time in that city.

And here's how you could use it:


#!/usr/bin/perl

use Clock;

$london = new Clock;
$london->set_offset("+", 0, 00, "London");
$london->display();

$bombay = new Clock;
$bombay->set_offset("+", 5, 30, "Bombay");
$bombay->display();

$sydney = new Clock;
$sydney->set_offset("+", 11, 00, "Sydney");
$sydney->display();

$us_ct = new Clock;
$us_ct->set_offset("-", 6, 00, "US/Central");
$us_ct->display();


And the output is:


Local time in London is 8:10:1
Local time in Bombay is 13:40:1
Local time in Sydney is 19:10:1
Local time in US/Central is 2:10:59


It should be noted here that it is also possible to directly adjust the offset values without using the set_offset() method. For example, the line


$bombay->set_offset("+", 5, 30, "Bombay");


is technically equivalent to


$bombay->{offsetSign} = "+";
$bombay->{offsetH} = 5;
$bombay->{offsetM} = 30;
$bombay->{city} = "Bombay";


Notice I said "technically". It is generally not advisable to do this, as it would violate the integrity of the object; the preferred method is always to use the methods exposed by the object to change object properties.

Just as an illustration - consider what would happen if the author of the Clock.pm module decided to change the variable name $offsetH to $OFFSETh - you would need to rework your test script as well, since you were directly referencing the variable $offsetH. If, on the other hand, you had used the set_offset() method, the changes to the variable name would be reflected in the set_offset() method by the author and your code would require no changes whatsoever.

By limiting yourself to exposed methods, you are provided with a level of protection which ensures that changes in the package code do not have repercussions on your code.


One of the main virtues of object-oriented programming is that it allows you to re-use existing objects, and add new capabilities to them - a feature referred to as "inheritance". By creating a new object which inherits the properties and methods of an existing object, developers can build on existing Perl packages, and reduce both development and testing time.

As an example, let's create a new package, AlarmClock, which inherits from the base class Clock.


package AlarmClock;

# tell the new package to use the Clock.pm module
require Clock;

# make methods available from "Clock"
@ISA=("Clock");

1;


At this point, you should be able to do this


#!/usr/bin/perl

require AlarmClock;

$mumbai = new AlarmClock;

$mumbai->set_offset(5,30, "Bombay");

$mumbai->display;


and have the code work exactly as before, despite the fact that you are now using the AlarmClock package. This indicates that the package AlarmClock has successfully inherited the properties and methods of the package Clock. This is referred to as the "empty sub-class test" - essentially, a new class which functions exactly like the parent class, and can be used as a replacement for it (obviously, this is not very useful, and I'll be adding new methods to AlarmClock soon.)

The @ISA array that you see above is a special Perl array which indicates the class from which methods and properties are to be inherited - in this case, "Clock".

Now, how about adding a new method to the AlarmClock package?


package AlarmClock;

# this tells it to use the Clock.pm module
require Clock;

# this makes methods available
@ISA="Clock";

# simple subroutine to increase the value of the "hours" variable by one
sub adjustHoursByOne
{
my $self=shift;
$self->{offsetH}++;
}

1;


And let's add this to the test script as well:


#!/usr/bin/perl

require AlarmClock;

$mumbai = new AlarmClock;
$mumbai->set_offset(5,30, "Bombay");
$mumbai->display;
$mumbai->adjustHoursByOne;
$mumbai->display;


And here's the output you'll probably see:


Local time in Bombay is 15:21:32
Can't locate object method "adjustHoursByOne" via package "Clock"


You're probably thinking, "Duh? What's this all about?". Let me explain.


In order for a child class to derive methods and properties correctly from the parent, the parent class' constructor needs to bless references into the child class correctly. If you take a look at the original constructor from Clock.pm, you'll see that it looks like this:


# constructor
sub new
{

my $self = {};

# define variables to store timezone offset from GMT, in hours and minutes,
# and city name
$self->{offsetSign} = undef;
$self->{offsetH} = undef;
$self->{offsetM} = undef;
$self->{city} = undef;

bless($self);
return $self;
}


In this case, the bless() function blesses the reference $self directly into the same class...which creates a problem when the class is inherited. To solve this problem, you can bless the reference into any requesting class by using the extended form of bless(), or


bless($self, $class);


where $class is the name of the class $self is bless()ed into.

And where does $class come from? It's passed to the new() constructor at the time the object is created, and you can access it like this:


# constructor
sub new
{

# get calling class name
my $class = shift;

my $self = {};

# define variables to store timezone offset from GMT, in hours and minutes,
# and city name
$self->{offsetSign} = undef;
$self->{offsetH} = undef;
$self->{offsetM} = undef;
$self->{city} = undef;

bless($self, $class);
return $self;
}


And now, when you try the test script, you should see the following output:


Local time in Bombay is 13:51:40
Local time in Bombay is 14:51:40


Obviously, your child classes can have their own constructors, which you can use to define variables specific to the child class.


Now, while inheritance might not seem like a very big deal, it can blow up in your face at times. For example, look what happens if I add a new display() method to the AlarmClock package:


package AlarmClock;

# lots of code

sub display
{
print "This clock is broken. Aargh!!\n";
}

1;


In this case, when I run the test script


#!/usr/bin/perl

require AlarmClock;

$mumbai = AlarmClock->new;
$mumbai->set_offset(5,30, "Bombay");
$mumbai->display;


the output reads


This clock is broken. Aargh!!


or, in other words, the display() method called belongs to AlarmClock, not Clock.

If I specifically want to run the display() method from the package Clock, I have to use an "override" like this:


#!/usr/bin/perl

require AlarmClock;

$mumbai = AlarmClock->new;
$mumbai->set_offset(5,30, "Bombay");
$mumbai->Clock::display;


By preceding the method with the package name, I can control which display() method is called.


And finally, destructors. In Perl, an object is automatically destroyed once the references to it are no longer in use, or when the Perl script completes execution. A destructor is a special function which allows you to execute commands immediately prior to the destruction of an object.

You do not usually need to define a destructor - but if you want to see what it looks like, take a look at this:


package AlarmClock;

# lots of code

sub DESTROY
{
print "I'm outta here!\n";
}

1;


Note that a destructor must always be called DESTROY - yes, all caps!

And if you were to run the test script above again, your output would look like this:


Local time in Bombay is 15:33:12
I'm outta here!

Оставьте свой комментарий !

Ваше имя:
Комментарий:
Оба поля являются обязательными

 Автор  Комментарий к данной статье