3

我已经编写了一些 Perl 代码,这些代码由一个基础类所固有的两个类组成。我想它会打印这样的东西

Mik: Meow! Meow!
Sat: Woof! Woof!

但它实际上是这样打印的:

Sat: Woof! Woof!
Sat: Woof! Woof!

,

package Animal;
sub new {

    my $obj = shift;
    my $name = shift;
    our %pkg = ( 'name' => $name );
    bless \%pkg, $obj;
    return \%pkg;
}

package Cat;
@ISA = ("Animal");

sub new {
    my $obj = shift;
    my $name = shift;
    my $self =  $obj->SUPER::new($name);
    return $self;
}

sub get_name {
    my $obj = shift;
    return $obj->{'name'};
}


sub talk {
    my $obj = shift;
    return "Meow! Meow!";
}

package Dog;
@ISA = ("Animal");

sub new {
    my $obj = shift;
    my $name = shift;
    my $self = $obj->SUPER::new( $name );
    return $self;
}

sub get_name {
    my $obj = shift;
    return $obj->{'name'};
}

sub talk {
    my $obj = shift;
    return "Woof! Woof!";
}

package Main;

my $cat = new Cat('Mike');
my $dog = new Dog('Sat');

print $cat->get_name() . ": " . $cat->talk() , "\n"; 
print $dog->get_name() . ": " . $dog->talk() , "\n";

但是,如果我以这种方式更改调用者,它会打印出我认为的内容。所以很奇怪为什么在实例化$cat之后对象被覆盖了$dog

package Main;

my $cat = new Cat('Mily');
print $cat->get_name() . ": " . $cat->talk() , "\n"; 

my $dog = new Dog('Sat');
print $dog->get_name() . ": " . $dog->talk() , "\n";
4

3 回答 3

8

为什么要祝福成一个全局变量?将您的构造函数更改为:

sub new {
    my $obj = shift;
    my $name = shift;
    my %pkg = ( 'name' => $name );
    bless \%pkg, $obj;
    return \%pkg;
}

更好的是,将其更改为更惯用的东西:

sub new {
    my $class = shift;
    my $name  = shift;
    my $self  = { name => $name };
    return bless $self, $class;
}

继续:

为什么要在每一种动物中实施new和?get_name这两种方法都可以继承。当我们这样做的时候,我们不妨摆脱混乱@ISA

package Animal;
sub new {
    my $class = shift;
    my $name  = shift;
    my $self  = { name => $name };
    return bless $self, $class;
}

sub get_name {
    my $self = shift;
    return $self->{'name'};
}

package Cat;
use base qw/ Animal /;

sub talk {
    my $self = shift;
    return "Meow! Meow!";
}

package Dog;
use base qw/ Animal /;

sub talk {
    my $self = shift;
    return "Woof! Woof!";
}

package Main;

my $cat = Cat->new('Mike');
my $dog = Dog->new('Sat');

print $cat->get_name() . ": " . $cat->talk() , "\n"; 
print $dog->get_name() . ": " . $dog->talk() , "\n";

请问您正在关注哪个教程或书籍?

虽然上述内容非常好,但您也可以使用 Modern Perl 的方式:

package Animal;
use Moose;
has name => ( required => 1, is => 'rw', isa => 'Str' );

package Cat;
use Moose;
extends 'Animal';

has talk => ( default => "Meow! Meow!", is => 'ro' );

package Dog;
use Moose;
extends 'Animal';

has talk => ( default => "Woof! Woof!", is => 'ro' );

package Main;
my $cat = Cat->new( name => 'Mike');
my $dog = Dog->new( name => 'Sat');

print $cat->name . ": " . $cat->talk , "\n"; 
print $dog->name . ": " . $dog->talk , "\n";
于 2013-07-04T14:34:14.970 回答
4

您已经声明了用于存储实例数据的变量

our %pkg

这是单个数据结构 ( %Animal::pkg) 的别名,因此您的所有对象都使用相同的哈希。更改ourmy以每次创建一个新的哈希。


可能值得注意的是,Perl 中的“由内而外”对象可以并且确实使用包中的共享数据结构来存储实例数据,但需要额外的抽象级别才能使其工作,我不推荐从它们开始 OO Perl,它们是后天习得的。

于 2013-07-04T14:34:53.940 回答
2

简而言之:our声明包变量,因此每次our %pkg = (...)执行时,您都会为同一个变量分配一个新值。由于所有\%pkg引用都指向同一个 var,所有的返回值new都是同一个对象。一个参考只能被祝福到一个类,所以最后一个获胜。

只需将 更改ourmy,它应该可以按预期工作。

于 2013-07-04T14:34:21.580 回答