¿Cómo heredo las subrutinas en Perl con ''use base''?
inheritance (6)
Como nota al margen, hay pocas buenas razones para use base
lugar del use parent
más reciente.
¿Cómo aplico ''use base'' en Perl para heredar subs desde algún módulo base?
Estoy acostumbrado a la mecánica de herencia C ++, y todos los sitios que busqué en Google para esto causaron más confusión y ayuda. Quiero hacer algo como lo siguiente:
#! /usr/bin/perl
#The base class to inherit from
use strict;
use warnings;
package ''TestBase'';
#-------------------------------
sub tbSub
{
my ($self, $parm) = @_;
print "/nTestBase: $parm/n";
}
1;
.
#! /usr/bin/perl
#The descendent class
use strict;
use warnings;
use base qw(TestBase);
sub main;
sub mySub;
#-------------------------------
#Entry point...
main();
#---code------------------------
sub main
{
mySub(1);
tbSub(2);
mySub(3);
}
#-------------------------------
sub mySub
{
my $parm = shift;
print "/nTester: $parm/n";
}
Perl se queja / no puede encontrar tbSub.
La herencia de Perl hereda métodos , no funciones. Eso significa que deberás llamar
main->tbSub(2);
Sin embargo, lo que realmente quieres es heredar el método en una clase adecuada:
package Derived;
use base "TestBase";
package main;
Derived->somemethod("foo");
Los métodos de llamada en el paquete actual como funciones no pasarán en el $ self o "este" objeto ni en el nombre de clase mágicamente. Internamente,
Class->somemethod("foo")
esencialmente termina siendo llamado como
Class::somemethod("Class", "foo")
internamente. Por supuesto, esto supone que Class tiene una subrutina / método llamado "algún método". De lo contrario, se verificarán las superclases de Clase y, si no tienen un método "algún método", se producirá un error grave. (Se aplica la misma lógica para el método $ obj-> ("foo")).
Los Mechnics de C ++ no son muy diferentes a la mecánica de Perl: para usar la herencia, necesitas dos clases: la clase base y la clase heredada. Pero no tienes ninguna clase descendiente.
También le falta un constructor. A diferencia de C ++, Perl no proporcionará un constructor predeterminado para usted.
Tu clase base contiene un mal error de sintaxis, así que supongo que no has probado el código antes de publicarlo.
Finalmente, como ya se observó, deberá informar a Perl si desea una llamada de función o una llamada a un método.
Lo que realmente quieres sería algo como esto:
my $foo = TestDescendent->new();
$foo->main();
package TestBase;
sub new {
my $class = shift;
return bless {}, $class;
}
sub tbSub
{
my ($self, $parm) = @_;
print "/nTestBase: $parm/n";
}
package TestDescendent;
use base ''TestBase'';
sub main {
my $self = shift;
$self->mySub( 1 );
$self->tbSub( 2 );
$self->mySub( 3 );
}
sub mySub
{
my $self = shift;
my $parm = shift;
print "/nTester: $parm/n";
}
1;
Me parece que estás mezclando dos cosas aquí: Perl orientada a objetos y procesal. Perl OO es algo así como "diferente" (como no convencional pero viable).
Parece que su módulo TestBase.pm se ejecutará como un objeto Perl (Perl oo-style), pero su script Perl quiere acceder a él como un módulo "normal". Perl no funciona de la forma en que lo hace C ++ (como se dio cuenta) por lo que tendría que construir su código de manera diferente. Vea los libros de Damian Conway para obtener explicaciones (y un código más inteligente que el mío a continuación).
Procesal:
#! /usr/bin/perl
#The module to inherit from
package TestBase;
use strict;
use warnings;
use Exporter ();
our @ISA = qw (Exporter);
our @EXPORT = qw (tbSub);
#-------------------------------
sub tbSub
{
my ($parm) = @_;
print "/nTestBase: $parm/n";
}
1;
.
#! /usr/bin/perl
#The descendent class
use strict;
use warnings;
use TestBase;
sub main;
sub mySub;
#-------------------------------
#Entry point...
main();
#---code------------------------
sub main
{
mySub(1);
tbSub(2);
mySub(3);
}
#-------------------------------
sub mySub
{
my $parm = shift;
print "/nTester: $parm/n";
}
Perl OO
#! /usr/bin/perl
#The base class to inherit from
package TestBase;
use strict;
use warnings;
#-------------------------------
sub new { my $s={ };
return bless $s;
}
sub tbSub
{
my ($self,$parm) = @_;
print "/nTestBase: $parm/n";
}
1;
.
#! /usr/bin/perl
#The descendent class
use strict;
use warnings;
use TestBase;
sub main;
sub mySub;
#-------------------------------
#Entry point...
main();
#---code------------------------
sub main
{
my $tb = TestBase->new();
mySub(1);
$tb->tbSub(2);
mySub(3);
}
#-------------------------------
sub mySub
{
my $parm = shift;
print "/nTester: $parm/n";
}
La sintaxis OO utiliza el operador ->
para separar el mensaje y los argumentos del receptor del mensaje. Una breve ilustración a continuación.
You->do_something( @params );
OR
$you->do_something( @params );
package A;
sub do_neat_thing {
my ( $class_or_instance, @args ) = @_;
my $class = ref( $class_or_instance );
if ( $class ) {
say "Instance of ''$class'' does a neat thing.";
}
else {
say "$class_or_instance does a neat thing.";
}
}
...
package main;
A->do_neat_thing(); # A does a neat thing.
my $a_obj = A->new();
$a_obj->do_neat_thing(); # Instance of ''A'' does a neat thing.
Debería echarle un vistazo al uso de Moose, que es un sistema de objetos posmoderno para Perl5. Probablemente le resulte mucho más fácil captar que usar la semántica Perl OO estándar ... especialmente cuando proviene de otro lenguaje OO.
Aquí hay una versión de Moose de su pregunta ...
package TestBase;
use Moose;
sub tbSub {
my ($self, $parm) = @_;
print "/nTestBase: $parm/n";
}
package TestDescendent;
use Moose;
extends ''TestBase'';
sub main {
my $self = shift;
$self->mySub( 1 );
$self->tbSub( 2 );
$self->mySub( 3 );
}
sub mySub {
my ($self, $parm) = @_;
print "/nTester: $parm/n";
}
package main;
my $foo = TestDescendent->new();
$foo->main
Las diferencias son ...
- Constructor creado automáticamente para ti y
- Herencia definida por el comando "extends" en lugar de "use base".
Entonces este ejemplo solo cubre la punta del iceberg de Moose ;-)