2008-11-03 9 views
14

¿Cómo aplico 'use base' en Perl para heredar subs desde algún módulo base?¿Cómo heredo las subrutinas en Perl con 'base de uso'?

Estoy acostumbrado a la mecánica de herencia C++, y todos los sitios que busqué en Google para esto causaron más confusión que 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.

Respuesta

20

Las normas de C++ no son muy diferentes a las mecánicas de Perl: Para usar la herencia, necesita 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.

Su clase base contiene un mal error de sintaxis, por lo que supongo que no ha intentado con 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 quiere 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; 
4

La herencia de Perl hereda métodos, no funciones. Eso significa que usted tendrá que llamar

main->tbSub(2); 

Sin embargo, lo que realmente quiere es heredar el método en una clase propia:

package Derived; 
use base "TestBase"; 

package main; 
Derived->somemethod("foo"); 

llamar a métodos en el paquete actual como funciones no pasarán en el $ self o "este" objeto ni 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").)

+0

No, no termina así llamado - buscará la jerarquía de herencia por lo que puede llamar a un sub en un paquete completamente diferente. Además, sus ejemplos no son una sintaxis válida. (Sé lo que estabas tratando de decir, pero la forma en que lo dijiste confundirá a alguien tan confundido como el OP aún más). –

+0

Por supuesto, anda por el árbol de la herencia. La pregunta es acerca de la herencia después de todo. Tenga en cuenta que el OP está acostumbrado a usar la herencia de C++, así que pensé que sería obvio. – tsee

5

Me parece, se están mezclando dos cosas aquí: orientada a objetos y Procesal Perl. 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).


procedimiento:

#! /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"; 
} 
5

Como anotación al margen, hay pocas razones para use base en lugar de la más reciente use parent.

+0

Interesante. ¿Pero hay alguna buena razón para usar parent? – innaM

+0

Sí, mejor predictibilidad de lo que sucederá. base.pm combina un montón de comportamientos e intenta adivinar en algunas circunstancias excepcionales. Es poco probable que te encuentres con los problemas que esto puede causar, pero cuando lo haces, muerde. parent.pm no falla misteriosamente. –

+0

Bastante justo. ¡Gracias! – innaM

10

Debería echar 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 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 crea automáticamente &
  • definido por herencia "se extiende" comando en lugar de "usar base".

Así que este ejemplo solamente cubre la punta del iceberg Moose ;-)

1

sintaxis OO utiliza el operador -> para separar el mensaje y argumentos desde el 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. 
+0

No hay restricciones sobre el uso de otros módulos antes 'use base'. – Ether

Cuestiones relacionadas