第十二章 对象(上)

第十二章 对象(上)

对象是一个数据结构, 带有一些行为。我们通常把这些行为成为对象的直接动作,


类和实例方法 通过第一个参数区分,对于 Perl 而言,方法就是方法,只是由其第一个参数的类型来区分。


一个类可以从父类中继承方法,父类也叫基类或者超级类。


原则--所有对象的访问都应该只通过方法,


12.2 Perl 的对象系统


一个对象只不过是一个引用...恩,就是引用。

因为引用令独立的标量代表大量的数据,


一个类只是一个包


一个包当作一个类——通过使用包的子过程来执行类的方法,以及通过使用包的 变量来保存类的全局数据。通常,
使用一个模块来保存一个或者更多个类。
一个方法只是一个子过程


12.3 方法调用

如果用一个类调用该方法,那个参数 将会是类的名字。如果用一个对象调用方法,那个参数就是对象的引用。


对于类方法而言,调用者是包的名字。对于一个实例方法,调用者是 调用
者是一个声明对象的引用


12.3.1 使用箭头操作符的方法调用
INVOCANT->METHOD(LIST)
INVOCANT->METHOD


INVOCANT 是一个包的 名字的时候,我们把那个被调用的METHOD 看作类方法。

比如,使用类方法 summon 的构造一个类,然后在生成的对象上调用实例方法 speak,你 可以这么说:

$mage = Wizard->summon("Gandalf"); # 类方法
$mage->speak("friend")  # 实例方法



12.3.2 使用间接对象的方法调用


12.3.4 引用包的类

12.4 构造对象

所有对象都是引用,但不是所有引用都是对象

把一个引用和一个包名字标记起来(因此也和 包中的类标记起来了,因为一个类就是一个包)
的动作被称作赐福(blessing),你可以把 赐福(bless)看作把一个引用转换成一个对象


bless 函数接收一个或者两个参数。第一个参数是一个引用,而第二个是要把引用赐福 (bless)成的包。如果忽
略第二个参数,则使用当前包。

Vsftp:/root/perl/8# cat Critter.pm 
package Critter;
sub new {
my $self = {'a'=>11,'b'=>22}; # 指向一个空的匿名散列
bless $self, "Critter"; # 把那个散列作成一个 Critter 对象
return $self; # 返回新生成的 Critter
};
1;
Vsftp:/root/perl/8# cat a1.pl 
unshift(@INC,"/root/perl/8");
use Critter;
use Data::Dumper;
$pet = Critter->new;
print Dumper($pet);
print "
";
print $pet->{"a"};
print "
";

Vsftp:/root/perl/8# perl a1.pl 
$VAR1 = bless( {
                 'a' => 11,
                 'b' => 22
               }, 'Critter' );

11


12.4.1 可继承构造器

和所有方法一样,构造器只是一个子过程,但是我们不把它看做一个子过程。

在这里例子里,我们总是把它当作一个方法来调用

---类方法,因为调用者是一个包名字。


方法调用和普通的子过程调用有两个区别。

12.4.2 初始器

Vsftp:/root/perl/8# cat a2.pl 
sub fun1 {
       print "@_ is @_
";
      my $a1=shift;
      print "$a1 is $a1
";
       print "@_ is @_
";
    };
fun1(1,2,43,434);
Vsftp:/root/perl/8# perl a2.pl 
@_ is 1 2 43 434
$a1 is 1
@_ is 2 43 434


sub new {
my $invocant = shift;  ##从@_中取出第一个元素 类的名字
my $class = ref($invocant) || $invocant;
my $self = { @_ }; # 剩下的参数变成属性
bless($self, $class); # 给予对象性质
return $self;
}

Vsftp:/root/perl/8# cat Horse.pm 
package Horse;
sub new {
print "@_ is @_
";
my $invocant = shift;  ##从@_中取出第一个元素 类的名字
print "$invocant is  $invocant
";
print "@_ is @_
";
my $class = ref($invocant) || $invocant;
my $self = { @_ }; # 剩下的参数变成属性
bless($self, $class); # 给予对象性质
return $self;
};
1;

Vsftp:/root/perl/8# cat a3.pl 
unshift(@INC,"/root/perl/8");
use Horse;
use Data::Dumper;
$stallion = Horse->new(color => "black");
print Dumper($ed);


Vsftp:/root/perl/8# perl a3.pl 
@_ is Horse color black
$invocant is  Horse
@_ is color black
$VAR1 = undef;



12.5 类继承

对Perl的对象系统剩下的内容,从一个类继承另外一个类并不要给这门语言增加特殊的语法。

当你调用一个方法,如果perl 在调用者的包里找不到这个子过程,那么它就检查@ISA数组

Horse类继承Critter (父类 或称为基类):

Vsftp:/root/perl/9# cat Horse.pm 
package Horse;
our @ISA = "Critter";
sub new {
my $invocant = shift;
my $class = ref($invocant) || $invocant;
my $self = {
color => "bay",
legs => 4,
owner => undef,
@_, # 覆盖以前的属性
};
return bless $self, $class;
};
sub sum_arr {
       $self=shift;
       my $a=shift;
       my $b=shift;
       return $a + $b + 7;
};
1;
Vsftp:/root/perl/9# cat Critter.pm 
package Critter;
sub new {
    my $self = {};
    my $invocant = shift;    
my $class = ref($invocant) || $invocant;
	my ($name)=@_;    
      my $self = {    
         "name" =>$name    
                 };  
    bless $self, $class; # Use class name to bless() reference
    return $self;

};

sub sum {
       $self=shift;
       my $a=shift;
       my $b=shift;
       return $a + $b;
};
1;
Vsftp:/root/perl/9# cat a1.pl 
unshift(@INC,"/root/perl/9"); 
use Horse;;
use Critter;
use Data::Dumper;
$ed = Horse->new; # 四腿湾马
print $ed->sum_arr(4,5);
print "
";
print $ed->sum(4,5);
print "
";

Vsftp:/root/perl/9# perl a1.pl 
16
9

你现在应该可以在原先Critter 使用的任何地方使用Horse类或者对象了




当你调用一个方法的时候,如果 Perl 在调用者的包里找不到这个子过程, 那么它就检查 @ISA 数组(


Perl 是这样实现继承的:一个包的 @ISA 数组里的每个元素都保存另外一个包的名字,


package Horse;
our @ISA = "Critter";

把 Horse 类变成 Critter 类的子类

Critter  是父类或者称为基类

假设你在 $steed 里有一个 Horse 对象,并且在他上面调用了一个 move:
$steed->move(10);
因为 $steed 是一个 Horse,Perl 对该方法的第一个选择是 Horse::move 子过程。如果 没有,Perl 先询问
@Horse::ISA 的第一个元素,而不是生成一个运行时错误,这样将导致 查询到 Critter 包里,并找到
Critter::move。如果也没有找到这个子过程,而且 Critter 有自己的 @Critter::ISA 数组,那么继续查询那里面
的父类,看看有没有一个 move 方法,如此类推直到上升到继承级别里面一个没有 @ISA 的包

原文地址:https://www.cnblogs.com/hzcya1995/p/13350003.html