Copyrigtht © 2000 Universita' di Firenze. All rights reserved.
Free license available.
Revisori: Prof. Franco Pirri 
 , Ing. Claudio Bizzarri ![]()
|
Cerchiamo di capire il funzionamento dell'ereditarietà con un semplice esempio:
package Persona;
sub new
{
my $primo_par = shift;
my $classe = ref($primo_par) || $primo_par;
my $this = {};
bless ($this, $classe);
return $this;
}
package Studente;
@ISA = qw(Persona);
package main;
$persona = Persona->new();
$studente =Studente->new();
$oggetto1 = ref($persona);
$oggetto2 = ref($studente);
print "$oggetto1\n"
print "$oggetto2\n";
Andando ad eseguire questo codice si ottiene la stampa a video di:
Persona
Studente
Con l'istruzione
$persona = Persona->new();
si invoca l'esecuzione del metodo costruttore della classe Persona, cioè di un
metodo che è effettivamente implementato in tale classe.
Al contrario con l'istruzione
$studente = Studente->new();
si invoca un metodo che non è stato definito nella classe Studente.
In questo caso l'interprete del Perl controlla se nella classe Studente è stato
definito l'array @ISA e, se è definito, lo consulta per vedere se esiste una
classe da cui Studente eredita che può fornirgli tale metodo.
Ovviamente, nel nostro caso, l'interprete trova che il metodo new() è implementato
nella classe Persona (l'unica presente in @ISA) e quindi lo esegue.
Fra poco spiegheremo come avvenga la ricerca di un metodo non definito in una
classe ma prima dobbiamo chiarire un altro punto.
Abbiamo stabilito che l'invocazione del metodo new() sulla classe Persona
e sulla classe Studente comporta l'esecuzione della stessa funzione, cioè la
funzione new() implementata in Persona: come mai allora ci accorgiamo che
$persona è un reference a un oggetto della classe Persona e che invece
$studente è un reference a un oggetto della classe Studente?
La spiegazione si può trovare analizzando l'implementazione del costruttore new()
e, in particolare, il modo in cui viene utilizzata al suo interno la funzione
bless().
Il costruttore accetta come primo parametro o il reference ad un oggetto o il nome di una
classe e memorizza nella variabile $classe il nome della classe da cui il metodo
è stato invovato.
Successivamente la funzione bless() benedice il reference al coso appena creato
($this) con il nome della classe contenuto in $classe
bless ($this, $classe);
in questo modo ogni nuovo oggetto apparterrà alla classe da cui il metodo new()
viene invocato.
Osservazioni
Sulla base di questo esempio si comprende che, per poter sfruttare il meccanismo
dell'ereditarietà, non si deve mai vincolare un costruttore ad utilizzare il nome
esplicito della classe che deve benedire.
L'esempio riportato illustra il funzionamento dell'ereditarietà singola. L'ereditarietà
multipla viene trattata in modo del tutto analogo: è sufficiente che l'array @ISA
contenga la lista di tutte le classi base da cui la nuova classe deve ereditare.
![]() |
Ogni nuova classe eredita implicitamente i metodi messi a disposizione dalla classe UNIVERSAL tra cui:
![]() |
Quando si invoca un metodo di una classe l'interprete del Perl segue la seguente sequenza di ricerca per trovare il punto in cui il metodo stesso è stato definito:
Studente::visualizza Persona::visualizza UNIVERSAL::visualizza Studente::AUTOLOAD Persona::AUTOLOAD UNIVERSAL::AUTOLOAD
![]() |
Quando si definisce una classe derivata a partire da una classe base spesso si presenta
la necessità di dover modificare il suo costruttore (rispetto a quello della classe base)
per poter aggiungere ulteriori attributi alla nuova classe oltre a quelli ereditati.
Cerchiamo di mostrare come ciò sia possibile riprendendo il nostro esempio.
Supponiamo di avere quindi la classe base Persona caratterizzata dagli attributi
nome e cognome e di voler derivare da essa la nuova classe Studente
che, oltre agli attributi ereditati, possieda anche l'attributo matricola.
Questo risultato si può ottenere nel modo seguente:
package Persona;
sub new
{
my $primo_par = shift;
my $classe = ref($primo_par) || $primo_par;
my ($nome, $cognome) =@_;
my $this = {};
$this->{'nome'} = $nome;
$this->{'cognome'} = $cognome;
bless($this, $classe);
return $this;
}
package Studente;
@ISA = qw(Persona);
sub new
{
my $primo_par = shift;
my $classe = ref($primo_par) || $primo_par;
my ($nome, $cognome, $matricola) = @_;
$this = Studente->Persona::new($nome, $matricola);
$this->{'matricola'} = $matricola;
return $this;
}
Se analizziamo il costruttore della classe Studente possiamo osservare che:
$this = Studente->Persona::new($nome, $cognome);In pratica con questa istruzione si passa Studente come primo parametro al metodo new() della classe Persona: in tal modo viene creato un nuovo oggetto appartenente alla classe desiderata (cioè Studente) e vengono valorizzati i suoi attributi nome e cognome.
$this = Studente->Persona::new($nome, $cognome);possiamo notare che ci sono due inconvenienti:
$this = $classe->Persona::new($nome, $classe);
$this = $classe->SUPER::new($nome, $cognome);