3

基本クラスから固有の 2 つのクラスを構成する 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

なぜグローバル変数に bless するのですか? コンストラクターを次のように変更します。

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) のエイリアスであるため、すべてのオブジェクトが同じハッシュを使用しています。毎回新しいハッシュを作成するには、 に変更ourします。my


Perl の「インサイドアウト」オブジェクトは、パッケージ内の共有データ構造を使用してインスタンス データを格納できることに注意してください。それらでOO Perlを開始すると、それらは後天的な味です。

于 2013-07-04T14:34:53.940 に答える
2

一言で言えば:パッケージ変数を宣言するので、が実行されるourたびに、同じ変数に新しい値を割り当てます。our %pkg = (...)すべての\%pkg参照が同じ var を指しているため、 のすべての戻り値はnew同じオブジェクトです。参照は 1 つのクラスにのみ bless できるため、最後のクラスが優先されます。

を に変更するだけourmy、期待どおりに動作するはずです。

于 2013-07-04T14:34:21.580 に答える