Perl 的继承
Perl 类的定义
Perl的一个packag可以作为一个类使用,文件后缀名为.pm,并且把package里的函数当作类的方法来用。如:
package Person;
创建和使用对象
大多数程序使用类名作为构造函数,Perl 中可以使用任何名字。
你可以使用多种 Perl 的变量作为 Perl 的对象。大多数情况下我们会使用引用数组或哈希。
接下来我们为 Person 类创建一个构造函数,使用了 Perl 的哈希引用。如:
package Person;
sub new
{
my $class = shift;
my $self = {
_firstName => shift,
_lastName => shift,
_ssn => shift,
};
# 输出用户信息
print "名字:$self->{_firstName}\n";
print "姓氏:$self->{_lastName}\n";
print "编号:$self->{_ssn}\n";
bless $self, $class;
return $self;
}
接下来我们创建一个对象:
$object = new Person( "小明", "王", 23234345);
也可以使用如下方法创建对象:
$object = Person->new( "小明", "王", 23234345);
定义方法
Perl类的方法只是个Perl子程序而已,也即通常所说的成员函数。
Perl面向对象中Perl的方法定义不提供任何特别语法,但规定方法的第一个参数为对象或其被引用的包。
Perl 没有提供私有变量,但我们可以通过辅助的方式来管理对象数据。(比如通过方法中的第一个参数也就是对象或者引用的包的哈希来保存私有变量),如下所示:
sub setFirstName {
my ( $self, $firstName ) = @_;
$self->{_firstName} = $firstName if defined($firstName);
return $self->{_firstName};
}
修改Person.pm 如下:
#!/usr/bin/perl package Person; sub new
{
my $class = shift;
my $self = {
_firstName => shift,
_lastName => shift,
_ssn => shift,
};
# 输出用户信息
print "名字:$self->{_firstName}\n";
print "姓氏:$self->{_lastName}\n";
print "编号:$self->{_ssn}\n";
bless $self, $class;
return $self;
}
sub setFirstName {
my ( $self, $firstName ) = @_;
$self->{_firstName} = $firstName if defined($firstName);
return $self->{_firstName};
} sub getFirstName {
my( $self ) = @_;
return $self->{_firstName};
}
1;
Perl继承
Perl 里 类方法通过@ISA(Perl内置数组)数组继承,这个数组里面包含其他包(类)的名字,变量的继承必须明确设定。
多继承就是这个@ISA数组包含多个类(包)名字。
通过@ISA只能继承方法,不能继承数据。但是EXPORT可以是方法,也可以是数据,参见文章“Perl中神奇的@EXPORT”
接下来我们创建一个 Employee 类继承 Person 类。
#!/usr/bin/perl package Employee;
use Person;
use strict;
our @ISA = qw(Person); # 从 Person 继承 # 重写构造函数
sub new {
my ($class) = @_; # 调用父类的构造函数
my $self = $class->SUPER::new( $_[1], $_[2], $_[3] );
# 添加更多属性
$self->{_id} = undef;
$self->{_title} = undef;
bless $self, $class;
return $self;
} # 重写方法
sub getFirstName {
my( $self ) = @_;
# 这是子类函数
print "这是子类函数\n";
return $self->{_firstName};
} # 添加方法
sub setLastName{
my ( $self, $lastName ) = @_;
$self->{_lastName} = $lastName if defined($lastName);
return $self->{_lastName};
} sub getLastName {
my( $self ) = @_;
return $self->{_lastName};
} 1;
当在类中找不到某个实例方法时,它就会检查该类的 @ISA 是否被初始化。如果已经初始化了,它检查其中的某个模块是否支持这个“缺少”的函数。如果它按照深度优先的层次结构搜索 @ISA 数组并且发现同名的方法,它会调用第一个被发现的同名方法并将控制权交给它。我们利用 Perl 语言的这个特性实现了继承。
如上所示继承后子类增加了自己的方法,并且在子类中对方法进行了重写。
这里我们注意到在子类的构造函数中我们通过SUPER调用了基类的构造函数:
my $self = $class->SUPER::new( $_[1], $_[2], $_[3] );
我们也可以直接使用基类的类名来调用:
my $self = Person::new( $_[1], $_[2], $_[3] );
如果只知道父类的方法名,而不知道父类名,我们可以使用伪类保留字SUPER::
总结
通过在子类中use 基类,并将基类名放在内置数组@ISA中即可实现继承:
#!/usr/bin/perl package Employee; use Person;
use strict;
our @ISA = qw(Person); # 从 Person 继承
Perl 中的bless
从前面的代码中可以看到Perl类的构造函数使用了bless 函数。下面介绍其由来。
Perl不像其他的面向对象语言具有变量修饰符(public, private ,final...). 类属性只是包中的全局变量,而类方法则是不依赖于任何特定实例的普通子例程。如下为类方法和类属性的例子:
package Person; my $person_number = 0; sub new {
my $self = {};
shift;
my ($name, $age) = @_;
$self->{name} = $name;
$self->{age} = $age;
$person_number++;
bless ($self);
return $self;
} sub calculate_person_number { return $person_number; } my $object_personA = Person->new ( “ David ” , 27); my $object_personB = Person::new ( “ Tonny ” , 27); my $person_number = Person::calculate_person_number (); print “ We have ” . $person_number . “ persons in all. \n ” ;
因此,不能将实例的变量直接放在整个package中(否则将成为类变量)。我们只能这么做:
package Person;
sub new {
my ($name, $age) = @_;
my $r_object = {
“ name ” => $name,
“ age ” => $age
} return $r_object; } my $personA = Person->new ( “ Tommy ” , 22 ); my $personB = Person->new ( “ Jerry ” , 30 ); print “ Person A ’ s name: ” . $personA->{name} . “ age: ” . $personA->{age} . ” .\n ” ; print “ Person B ’ s name: ” . $personB->{name} . “ age: ” . $personB->{age} . ” .\n ” ;
那么问题来了:Perl 的编译器并不知道new 函数所返回的指向匿名哈希表的引用属于哪个类(模块)。这样的话,如果要使用类中的实例方法,只能直接标出方法所属于的类(模块)的名字,并将引用作为方法的第一个参数传递给它,如下所示:
package Person;
… sub change_name {
my ($self, $new_name) = @_;
$self->{name} = $new_name; } my $object_person = Person->new ( “ Tommy ” , 22); print “ Person ’ s name: ” . $object_person->{name} . “ .\n ” ; Person::change_name ($object_person, “ Tonny ” ); print “ Person ’ s new name: ” . $object_person->{name} . “ .\n ” ;
对于这个问题,Perl 中的 bless 函数提供了一个解决问题的桥梁。 bless 以一个普通的指向数据结构的引用为参数,它将会把那个数据结构(注意:此处不是引用本身)标记为属于某个特定的包,这样就赋予了这个匿名哈希表的引用以多态的能力。同时,我们使用箭头记号来直接调用那些实例方法,如下所示:
package Person
my $person_number = 0;
sub new {
my $self = {};
shift;
my ($name, $age) = @_;
$self->{name} = $name;
$self->{age} = $age;
bless ($self);
return $self;
} sub change_name {
my $self = shift;
my $name = shift;
$self->{name} = $name;
} sub getName {
my $self = shift;
return $self->{name};
} sub calculate_person_number { return $person_number; }
my $object_person = Person->new ( “ David ” , 27); print “ Name: “ . $object_person->{name} . “ \n ” ; $object_person->change_name ( “ Tony ” ); print “ Name: “ . $object_person->{name} . “ \n ” ; my $object_personA = Person->new ( “ David ” , 27); my $object_personB = Person::new ( “ Tonny ” , 27); my $person_number = Person::calculate_person_number (); print “ We have ” . $person_number . “ persons in all. \n ” ;
如上代码 中的“ bless ($self) ”,将指向一个匿名哈希表的引用标记为属于当前包,也就是 package Person 。
所以,当 Perl 看到“ $object_person->change_name ($name) ”时,它会决定 $object_person 属于 package Person 。 Perl 就会如下所示地调用这个函数,“ Person::change_name ($object_person, $name) "。
换而言之,如果使用箭头的方式调用一个函数,箭头左边的那个对象将作为相应子例程的第一个参数。 Perl 的实例方法的本质其实就是一个第一个参数碰巧为对象引用的普通子例程。
与实例方法不同,我们使用 Person::calculate_person_number () 的形式来调用类方法。这样的话,指向匿名哈希表的引用将不会作为第一个调用参数传入。
(从这里也可以看出::和->使用的区别,一个是类方法调用,一个是实例方法调用)
一般的bless是使用两个参数的,如下:
sub new {
my ($class) = @_; # 调用父类的构造函数
my $self = $class->SUPER::new( $_[1], $_[2], $_[3] );
# 添加更多属性
$self->{_id} = undef;
$self->{_title} = undef;
bless $self, $class;
return $self;
}
当第二个参数省略时默认为当前包。
参考文献:
http://www.cnblogs.com/A-Song/archive/2012/04/12/2443541.html
http://blog.sina.com.cn/s/blog_6151984a0100eq6e.html
http://www.runoob.com/perl/perl-object-oriented.html
Perl 的继承的更多相关文章
- Perl 和 Python 的比较 【转】
转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&id=4662991&uid=608135 作为万年Perl 党表示最近开 ...
- perl面向对象
来源: http://www.cnblogs.com/itech/archive/2012/08/21/2649580.html Perl面向对象 首先让我们来看看有关 Perl 面向对象编程 ...
- Perl中神奇的@EXPORT
@EXPORT Perl通过继承,可以使子类可以像使用本地方法一样使用其基类的方法. 一个类如果想把自己的方法(变量)暴露给别人使用(比如一些公共基础类的的通用方法或变量),还可将直接将方法(变量)添 ...
- Ruby. Vs . Python
前言:从语言的本质上来分析,我对Ruby持反对态度,毕竟语言是为了交流,在表达的效率层面为了正确性必须适当放弃复杂性.且有句老话说的好,Ruby In Rails 才是语言,而Ruby只是这个语言的工 ...
- perl 继承 @ISA
12.5 类继承 对Perl的对象剩下的内容而言,从一个类继承另外一个类并不需要给这门语法增加特殊的语法,当你调用一个方法的时候, 如果Perl在调用者的包里找不到这个字过程,那么他就检查@ISA数组 ...
- perl 继承概述
<pre name="code" class="html">[root@wx03 test]# cat Horse.pm package Horse ...
- perl use base 继承
centos6.5:/root/podinns/lib#cat First.pm package First; use base qw(Second); sub new { my $self = {} ...
- perl 继承小例子
<pre name="code" class="html"><pre name="code" class="ht ...
- perl 继承写法
use base (Critter); 和 BEGIN{ require Critter; @ISA=qw/Critter/; } 这两种写法是等价
随机推荐
- 亚洲唯一,阿里云SLB位列Gartner全球网络负载均衡市场前五
近日,Gartner发布了最新的全球企业级网络设备市场份额报告“Market Share: Enterprise Network Equipment by Market Segment, Worldw ...
- 洛谷 1463[SDOI2005] 反素数ant
题目描述 对于任何正整数x,其约数的个数记作g(x).例如g(1)=1.g(6)=4. 如果某个正整数x满足:g(x)>g(i) 0<i<x,则称x为反质数.例如,整数1,2,4,6 ...
- 从零学React Native之11 TextInput
TextInput 组件是用来通过键盘输入文字,可以使用View组件和Text组件样式,没有自己特定的样式. 与Text组件类似,TextInput组件内部的元素不再使用FlexBox布局,而采用文本 ...
- POJ-1125_Stockbroker Grapevine
Stockbroker Grapevine Time Limit: 1000MS Memory Limit: 10000K Description Stockbrokers are known to ...
- 《C语言深度解剖》学习笔记之指针和数组
第4章 指针和数组 1. int *p=NULL 和 *p=NULL 有什么区别 int *p = NULL; 第一句代码的意思是:定义一个指针变量p,其指向的内存里面保存的是 int类型的数据:在定 ...
- vue init定制团队模板使用方法
每次做项目都要自己搭建项目目录,或者换了公司就的重新搭建项目目录,是不是很麻烦呢?有没有想过一次性把项目目录搭建好,以后直接用呢?你首先想到的可能是复制自己原来的项目,然后删除.修改等等.然而有个更方 ...
- IntelliJ IDEA和Eclipse设置JVM运行参数
打开 IDEA 安装目录,看到有一个 bin 目录,其中有两个 vmoptions 文件,需针对不同的JDK进行配置: 32 位:idea.exe.vmoptions64 位:idea64.exe.v ...
- hdu 2410 Barbara Bennett's Wild Numbers
Problem - 2410 挺好玩的一道题目.这道题的意思是给出一个模糊值以及一个确定值,要求求出模糊值中大于确定值的个数有多少. 这题我是直接用dfs的方法搜索的,对于每一位如果之前位置的形成的数 ...
- Laravel 之搜索引擎elasticsearch扩展Scout
简介 Laravel Scout 是针对Eloquent 模型开发的一个简单的,基于驱动的全文检索系统.Scout 使用模型观察者时会自动保持你的检索索引与你的 Eloquent 记录同步. 目前,S ...
- There is no getter for property named 'XXX' in 'class java.lang.String'
实验环境:spring boot+mybitis 由于采用的不带映射xml文件的模式,因此 方法1: 把#{xxx}修改为 #{_parameter} 即可 select count(*) from ...