一、继承
对于已经习惯了面向对象编程的人应该不再陌生了。继承是其一个主要的特性,增加代码的重用从而提高软件的性能。
简单的说模块是包,包是类。在C++中的类中都存在一个构造函数,perl也是(当然也可以没有)。一般的perl模块的构造函数如下
Sub new{
My $this={};
Bless $this;
Return $this;
}
但是如果想这个模块派生出另一个模块,这样就不可以,应该在创建的时候就容许其被继承,就必须保证有不同的类型可以被传入到new函数中来,那就以上构造函数改为
Sub new{
$type=shift;
$class=ref($type)||$type;
My $this={};
Bless $this,$class;
Return $this;
}
Bless是可以有两个参数的,第二个可选的,如果没有写第二个参数,就是和本模块相bless,写了,就是和已写的类型相bless。可以多次bless一个引用对象,然而,新的将被bless的类必然把对象已被bless的引用去掉,就像在C中把一块内存赋给一指针,再把另一块内存赋给同一个指针,而没有释放前一块内存。记住,一个perl对象每一时刻只能属于一个类。
Perl类的方法只不过是一个Perl子程序而已,称之为成员函数。Perl的方法的定义不提供任何特殊语法,但规定方法的第一个参数为对象或其被引用的包。Perl有两种方法:静态方法和虚方法。
静态方法
静态方法第一个为类的名称,即为模块名称,方法处理第一个参数的方式决定了是静态还是虚的。静态的方法一般会忽略第一个参数,方法知道是属于那个类,如下
Sub dosomething{
My ($modulename模块名称,$p1,…)=@_;
…
…
}
或是对象的引用
Sub dosomething{
$self=shift;
$self->{};
$self->funname();
Return $self;
}
我公司的基本是用这种。
虚方法:
虚方法通常首先把第一个参数shift到变量self或this中,然后将该值作普通的引用使用。
1. sub nameLister {2. my $this = shift;3. my ($keys ,$value );4. while (($key, $value) = each (%$this)) {5. print "/t$key is $value./n";6. }7. }
Perl类的继承是通过@ISA数组实现的。@ISA数组不需要在任何包中定义,然而,一旦它被定义,Perl就把它看作目录名的特殊数组。它与@INC数组类似,@INC是包含文件的寻找路径。@ISA数组含有类(包)名,当一个方法在当前包中未找到时就到@ISA中的包去寻找。@ISA中含有当前类继承的基类名。
类中调用的所有方法必须属于同一个类或@ISA数组定义的基类。如果一个方法在@ISA数组中未找到,Perl就到AUTOLOAD()子程序中寻找,这个可选的子程序在当前包中用sub定义。若使用AUTOLOAD子程序,必须用use Autoload;语句调用autoload.pm包。AUTOLOAD子程序尝试从已安装的Perl库中装载调用的方法。如果AUTOLOAD也失败了,Perl再到UNIVERSAL类做最后一次尝试,如果仍失败,Perl就生成关于该无法解析函数的错误。
下面是一个例子
package Employee;
###########################
#this class is father class
#is my test pro
###########################
use DDate;
###########################
#构造函数
###########################
sub new
{
my $type=shift;
#ref函数是返回参数是对什么对象的引用
#$class是对象的类型
my $class=ref($type)||$type;
my $hireDate=new DDate;
my $self={firstname=>undef,
lastname=>undef,
hireday=>$hireDate};
bless($self,$class);
return $self;
}
sub firstname
{
my $s=shift;
##就是带参数,参数是firstname
$s->{firstname}=shift() if(@_);
return $s->{firstname};
}
sub lasttname
{
my $s=shift;
##就是带参数,参数是firstname
$s->{lastname}=shift() if(@_);
return $s->{lastname};
}
sub hireday
{
my $s=shift();
if(@_)
{
$s->{hireday}->setdate(@_);
}else{
$s->{hireday}->myprint();
}
}
return 1;
子类
package Hourly;
use Employee;
our @ISA=("Employee");#our的作用就是全局化Employee
#Perl类的继承是通过@ISA数组实现的
#@ISA数组不需要在任何包定义,但是一旦它出现,perl在解释的时候就会把它看成目录#名的特殊数组。这与#@INC数组相似,@INC是包含文件的寻找路径。@ISA数组包有类#型名称。当一个方法在当前包中未找到时就到#@ISA中的包中去寻找,@ISA就包涵了基#类的名称,调用的方法是同一类或者包含于@ISA中,如果一个方法在数组无法找到,#perl就会到AUTOLOAD子程序寻找,要使用AUTOLOAD,必须显示的调用use Autoload;#如果AUTOLOAD也失败了,Perl再到UNIVERSAL类做最后一次尝试,如果仍失败,Perl 就生成关于该无法解析函数的错误。就是在构造函数的时候,有所不同,在构造函数中要构#造基类的,并把返回的#引用和子类的类型相绑定
sub new
{
my $c=shift();
my $t=ref($c)||$c;
my $s=$t->SUPER::new();
###这样就好理解了,就把Hourly类型作为一个参数传个基类Employee,
#####这样在基类的构造函数中,bless就把哈希的引用和这个类型相关联
#就是要把子类的类型和基类的哈希绑定
$s->{rate}=undef;
bless($s,$t);
return $s;
}
sub rate
{
my $s=shift();
$s->{rate}=shift if(@_);
return $s->{rate};
}
return 1;
###############################################################
#调用程序了
###############################################################
#!/usr/bin/perl
use Employee;
use Hourly;
my $work=new Employee;
$work->firstname("shi");
$work->lasttname("xiyun");
$work->hireday(1,25,1984);
print $work->firstname()." ". $work->lasttname()."/n";
$work->hireday();
my $w=new Hourly;
$w->firstname("Li");
$w->lasttname("weijiao");
$w->hireday(1,25,1985);
$w->rate(8.5);
print $w->firstname()." ". $w->lasttname()."/n";
$w->hireday();
print $w->rate()."/n";