Estudie este ejemplo:
1 #!/usr/bin/perl -d 2 3 package _I; 4 use strict; 5 6 sub new { 7 my ($class, %args) = @_; 8 my $self = bless {}, ref($class) || $class; 9 $self->_init(%args); 10 return $self; 11 } 12 13 package A; 14 @A::ISA = qw( _I); 15 16 sub _init { 17 my ($self, %args) = @_; 18 $self->{_a1} = $args{a1}; 19 $self->{_a2} = $args{a2}; 20 } 21 22 23 package B; 24 @B::ISA = qw( _I); 25 26 sub _init { 27 my ($self, %args) = @_; 28 $self->{_b1} = $args{b1}; 29 } 30 31 package C; 32 @C::ISA = qw( _I B A); 33 34 sub _init { 35 my ($self, %args) = @_; 36 $self->A::_init(%args); 37 $self->B::_init(%args); 38 $self->{_c1} = $args{c1}; 39 } 40 41 package main; 42 43 C->new(a1=>"a1", a2=>"a2", b1=>"b1", c1=>"c1");La idea es que la clase
_I
provee un constructor genérico. Las otras
clases heredan dicho constructor y no lo reescriben.
La figura 6.3 muestra el esquema de herencia
y el de delegación (flechas punteadas) usado para el método _init
.
Este esquema es posiblemente mas usual que el reemplazamiento completo del método por uno nuevo.
Véase una ejecución con el depurador:
$ ./inicializadores.pl Default die handler restored. Loading DB routines from perl5db.pl version 1.07 Editor support available. Enter h or `h h' for help, or `man perldebug' for more help. A::(./inicializadores.pl:14): @A::ISA = qw( _I); DB<1> n B::(./inicializadores.pl:24): @B::ISA = qw( _I); DB<1> C::(./inicializadores.pl:32): @C::ISA = qw( _I B A); DB<1> main::(./inicializadores.pl:43): C->new(a1=>"a1", a2=>"a2", b1=>"b1", c1=>"c1");el método
new
en la clase _I
acaba siendo llamado:
DB<1> s _I::new(./inicializadores.pl:7): my ($class, %args) = @_; DB<1> _I::new(./inicializadores.pl:8): my $self = bless {}, ref($class) || $class; DB<1> p $class C DB<2> n _I::new(./inicializadores.pl:9): $self->_init(%args);Obsérvese que:
C
, no en la clase
_I
.
new
llama al método _init
de la clase llamadora
(C->_init(%args)
no al método _init
de la clase _I
.
DB<2> s C::_init(./inicializadores.pl:35): my ($self, %args) = @_; DB<2> C::_init(./inicializadores.pl:36): $self->A::_init(%args);Las llamadas en las líneas 36 y 37 explicitan el paquete:
$self->A::_init(%args)
y $self->B::_init(%args)
.
Normalmente, cuando Perl comienza la busca
en el paquete en el cual ha sido bendecido el objeto, pero si
en la llamada con el operador flecha
se detalla el nombre completo del método
(fully qualified name)
Perl ignora la clase del objeto y comienza la búsqueda en la
tabla de símbolos del paquete prefijo.
DB<2> A::_init(./inicializadores.pl:17): my ($self, %args) = @_; DB<2> A::_init(./inicializadores.pl:18): $self->{_a1} = $args{a1}; DB<2> A::_init(./inicializadores.pl:19): $self->{_a2} = $args{a2}; DB<2> C::_init(./inicializadores.pl:37): $self->B::_init(%args); DB<2> B::_init(./inicializadores.pl:27): my ($self, %args) = @_; DB<2> B::_init(./inicializadores.pl:28): $self->{_b1} = $args{b1}; DB<2> C::_init(./inicializadores.pl:38): $self->{_c1} = $args{c1}; DB<2> _I::new(./inicializadores.pl:10): return $self; DB<2> p %$self _a2a2_b1b1_c1c1_a1a1 DB<3> Debugged program terminated. Use q to quit or R to restart, use O inhibit_exit to avoid stopping after program termination, h q, h R or h O to get additional info.El proceso de destrucción es equivalente. Puesto que se trata de métodos, se sigue el mismo algoritmo de búsqueda. Si queremos que los destructores sean llamados de manera organizada, es responsabilidad del programador el hacerlo.
Casiano Rodríguez León