Perl OO Superclass变量在打印时不绑定到子类对象

时间:2010-07-01 21:55:55

标签: perl

我正在做一个Perl OO示例(主要是为了重新使用Perl重新定义)并使用 继承,似乎SUPER在调用超类构造函数时在子类中工作 超类变量不绑定到子类对象。为什么会这样?

################################################
## Package : Person                          ##
################################################
package Person;

################################################
## Constructor                                ##
################################################
sub new(){

    my $class = shift;
    my $data = {};
    $data->{'firstName'} = shift;
    $data->{'secondName'} = shift;  
    bless $data, $class; 
    #bless $data, "Person"; #hack
    return $data;
}

################################################
## Getter Methods                            ##
################################################

sub getFirstName(){
  my $data = shift;
  return $data->{'firstName'};
}

sub getSecondName(){
  my $data = shift;
  return $data->{'secondName'};
}

################################################
## Setter methods                            ##
################################################

sub setFirstName($){
  my $data = shift;
  $data->{'firstName'} = shift;
}

sub setSecondName($){
  my $data = shift;
  $data->{'secondName'} = shift;
}

################################################
## Other Methods                              ##
################################################

sub printall(){
    my $data = shift;
    $\ = "\n";
    print "FirstName: ". $data->{'firstName'} ."\n";
    print "SecondName: ". $data->{'secondName'} ."\n";
}
1;

################################################
## Package : Coder                            ##
################################################

package Coder;
@ISA = qw( Person );
use strict;
use warnings;

################################################
## Constructor                                ##
################################################
sub new {
    my $class = shift;
    my $self = {};

    bless $self, $class;
    my $superFirstName = shift;
    my $superSecondName = shift;

    print "new superfirstname "  .$superFirstName;
    print "new supersecondname " .$superSecondName; 

    $self->{'language'} = shift; #i.e. Java 
    $self->{'experience'} = shift;  #number of years

    #$self = $self->SUPER::new($superFirstName, $superSecondName); 
    Person->new($superFirstName, $superSecondName);
    return $self;
}

################################################
## Getter Methods                            ##
################################################

sub getLanguage(){
  my $data = shift;
  return $data->{'language'};
}

sub getExperience(){
  my $data = shift;
  return $data->{'experience'};
}

################################################
## Setter methods                            ##
################################################

sub setLanguage($){
  my $data = shift;
  $data->{'language'} = shift;
}

sub setExperience($){
  my $data = shift;
  $data->{'experience'} = shift;
}

################################################
## Other Methods                              ##
################################################

sub printall(){
    my $data = shift;
    $\ = "\n";

    print "Experience: " . $data->{'experience'};
    print "Language: " . $data->{'language'};

    $data->SUPER::printall();

}
1;


################################################
## Package : Main                            ##
################################################
package main;

my $developer = Coder->new("John","Smith","Perl","2");

$developer->printall();

3 个答案:

答案 0 :(得分:3)

如果您打算将Coder继承自Person,那么您正在构建它 不正确。例如,在Coder的构造函数中,您将创建一个新的Person对象 扔掉它。这将是一种更好(更标准)的方式 构造一个继承自Person的Coder对象(参见perldoc perltoot):

sub new
{
    my $class = shift;
    my $this = $class->SUPER::new(shift, shift);

    # add on extra fields, now at the head of @_...

    bless $this, $class;
    return $this;
}

您可以进行许多改进:

  • 在人员中缺少use strict; use warnings;
  • use parent 'Person';而不是操纵@ISA
  • 函数原型很少是一个好主意(只有当你知道你需要它们时才使用它们,当编写面向对象的类时,这是永远 true,其中函数将被称为方法)
  • 您可以使用Class::Accessor自动生成访问者和变更器,而不是编写大量重复的样板文件

另外,虽然我不确定你是否准备好了(你应该明白这一点 首先是Perl OO构建的基础知识,你可以跳过几乎所有的写作 此代码使用Moose

package Person;
use Moose;
has [qw(firstName secondName)] => (
    is => 'rw', isa => 'Str',
);
no Moose;
__PACKAGE__->meta->make_immutable;
1;

package Coder;
use Moose;
extends 'Person';
has [qw(language experience)] => (
    is => 'rw', isa => 'Str',
);
no Moose;
__PACKAGE__->meta->make_immutable;
1;

答案 1 :(得分:3)

这是因为您没有对Person->new返回做任何事情。所以它只是创建一个整个其他Person对象,而Coder快乐地滑行。

你想做的是

my $self = $class->SUPER::new( $superFirstName, $superSecondName );

Person保佑它进入你传递的任何课堂 - 就像它一样。然后,在创建$self SUPER方式后,您需要为其添加所需的字段。

所以看起来应该是这样的:

use strict;
use warnings;

sub new {
    my $class = shift;
    my $superFirstName = shift;
    my $superSecondName = shift;
    print "new superfirstname "  .$superFirstName;
    print "new supersecondname " .$superSecondName; 

    my $self = $class->SUPER::new( $superFirstName, $superSecondName );
    # OR
    # $self = $class->Person::new( $superFirstName, $superSecondName );

    $self->{language}   = shift; #i.e. Java 
    $self->{experience} = shift;  #number of years

    return $self;
}

答案 2 :(得分:2)

Coder的构造函数没有意义;您正在调用Person->new,然后丢弃结果。这是一个更有用的模式:

package Coder;

sub new {
  my $class = shift;

  my $self = $class->SUPER::new(shift, shift); # firstname, lastname

  $self->{language} = shift;
  $self->{experience} = shift;

  $self;
}

是的,Person构造函数会在这种情况下将对象加入Coder,而不是加入Person - 这就是将类作为{{1的第一个参数}}

这是您的代码的最小更改版本,但我想在此之外提出一些建议:

  1. 构造函数的位置参数是确保没有人知道发生了什么的好方法。我建议输入new等。

  2. 您可能最好忘记所有这些苦差事并使用Moose:)