perl模块编程之继承

来源:互联网 发布:微信淘宝返利系统源码 编辑:程序博客网 时间:2024/05/21 08:51

一、继承

对于已经习惯了面向对象编程的人应该不再陌生了。继承是其一个主要的特性,增加代码的重用从而提高软件的性能。

简单的说模块是包,包是类。在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到变量selfthis中,然后将该值作普通的引用使用。

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";