2008-11-03 7 views
14

Wie wende ich 'use base' in Perl an, um Subs von einem Basismodul zu erben?Wie erben ich Subroutinen in Perl mit 'Base verwenden'?

Ich bin an C++ Vererbungsmechanik gewöhnt, und alle Websites, die ich dafür googelte, verursachten mehr Verwirrung als Hilfe. Ich möchte etwas wie das Folgende tun:

.

#! /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 klagt/kann tbSub nicht finden.

Antwort

20

Die C++ - Techniken sind nicht viel anders als die Perl-Mechanik: Um Vererbung zu verwenden, benötigen Sie zwei Klassen: die Basisklasse und die erbende Klasse . Aber Sie haben keine Nachkommenklasse.

Ihnen fehlt auch ein Konstruktor. Im Gegensatz zu C++ stellt Perl keinen Standardkonstruktor für Sie bereit.

Ihre Basisklasse enthält einen fehlerhaften Syntaxfehler. Ich nehme an, Sie haben den Code vor dem Senden nicht getestet.

Schließlich, wie bereits erwähnt, müssen Sie Perl wissen lassen, ob Sie einen Funktionsaufruf oder einen Methodenaufruf wünschen.

Was Sie wirklich so etwas wie dies aussehen würde wollen:

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

Perl Vererbung erbt Methoden, funktioniert nicht. Das heißt, Sie

main->tbSub(2); 

jedoch anrufen müssen, was Sie wirklich wollen, ist das Verfahren in eine richtige Klasse erben:

package Derived; 
use base "TestBase"; 

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

Aufrufen von Methoden im aktuellen Paket als Funktionen nicht passieren in das $ self oder "this" -Objekt oder der Klassenname magisch. Intern

Class->somemethod("foo") 

wesentlichen endet als

Class::somemethod("Class", "foo") 

intern aufgerufen wird. Dies setzt natürlich voraus, dass Class eine Subroutine/Methode namens "SomeMethod" hat. Wenn nicht, werden die Oberklassen von Class überprüft und wenn diese auch keine Methode "somemethod" haben, erhalten Sie einen fatalen Fehler. (Die selbe Logik gilt für $ obj-> method ("foo").)

+0

Nein, es endet nicht so genannt - es wird die Vererbungshierarchie nachschlagen, so dass ein Sub in einem komplett anderen Paket aufgerufen werden kann. Ihre Beispiele sind keine gültige Syntax. (Ich weiß, was du versucht hast zu sagen, aber wie du gesagt hast, es wird jemanden verwirren, der so verwirrt ist wie das OP noch weiter.) –

+0

Natürlich läuft es den Vererbungsbaum. Die Frage ist doch die Vererbung. Beachten Sie, dass das OP verwendet wird, um C++ Vererbung zu verwenden, also dachte ich, das wäre offensichtlich. – tsee

5

Es scheint mir, Sie vermischen hier zwei Dinge: Objektorientierte und Verfahrens Perl. Perl OO ist irgendwie "anders" (wie in nicht Mainstream aber praktikabel).

Ihr TestBase.pm-Modul scheint zu erwarten, dass es als Perl-Objekt (Perl oo-style) ausgeführt wird, aber Ihr Perl-Skript möchte als "normales" Modul darauf zugreifen. Perl funktioniert nicht so, wie C++ es tut (Sie haben es bemerkt), also müssten Sie Ihren Code anders konstruieren. Siehe Damian Conways Bücher für Erklärungen (und intelligenteren Code als meine unten).


Procedural:

#! /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

Als Nebenbei bemerkt, gibt es wenig Grund zu use base eher als die neueren use parent.

+0

Interessant. Aber gibt es einen guten Grund Eltern zu benutzen? – innaM

+0

Ja, bessere Vorhersagbarkeit dessen, was passieren wird. base.pm fasst eine Reihe von Verhaltensweisen zusammen und versucht in seltenen Fällen zu raten. Sie werden wahrscheinlich nicht auf die Probleme stoßen, die dies verursachen kann, aber wenn Sie es tun, beißt es. parent.pm scheitert nicht auf mysteriöse Weise. –

+0

Fair genug. Vielen Dank! – innaM

10

Sie sollten einen Blick auf Moose werfen, die ein postmodernes Objektsystem für Perl5 ist. Sie werden es wahrscheinlich leichter finden als die Standard-Perl-OO-Semantik ... besonders wenn Sie aus einer anderen OO-Sprache kommen.

Hier ist eine Moose Version Ihrer Frage ....

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 

Die Unterschiede sind ....

  • Constructor automatisch für Sie
  • Vererbung definiert durch "erweitert" & erstellt Befehl statt "Basis verwenden".

So dieses Beispiel deckt nur die Spitze des Eisbergs Moos ;-)

1

OO-Syntax verwendet den -> Operator die Nachricht und Argumente aus dem Empfänger der Nachricht zu trennen. Eine kurze Abbildung unten.

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

Es gibt keine Einschränkung für andere Module 'benutze die Basis'. – Ether