📄 perl 语言-perl 中文教程(第十三章).htm
字号:
<BLOCKQUOTE>
<P>/*<BR>** Created by Cocoa.pm<BR>** Use at own risk <BR>*/<BR>import
java.io.InputStream;<BR>import java.net.*;<BR><BR>public class Msg
extends java.applet.Applet implements Runnable {<BR>} </P></BLOCKQUOTE>
<P> 注意:如果用->操作符调用方法(也叫间接调用),参数必须用括号括起来,如:$cup->setImports(
'java.io.InputStream', 'java.net.*');而双冒号调用如:Cocoa::setImports($cup,
'java.io.InputStream', 'java.net.*');也可去掉括号写成:Cocoa::setImports $cup,
'java.io.InputStream', 'java.net.*' ;<BR><BR><A
name=8>八、重载</A><BR> 有时需要指定使用哪个类的方法,如两个不同的类有同名方法的时候。假设类Espresso和Qava都定义了方法grind,可以用::操作符指定使用Qava的方法:<BR> $mess
=
Qava::grind("whole","lotta","bags");<BR> Qava::grind($mess,
"whole","lotta","bags");<BR> 可以根据程序的运行情况来选择使用哪个类的方法,这可以通过使用符号引用去调用来实现:<BR> $method
= $local ? "Qava::" :
"Espresso::";<BR> $cup->{$method}grind(@args);<BR><BR><A
name=9>九、析构函数</A><BR> Perl跟踪对象的链接数目,当某对象的最后一个应用释放到内存池时,该对象就自动销毁。对象的析构发生在代码停止后,脚本将要结束时。对于全局变量而言,析构发生在最后一行代码运行之后。<BR> 如果你想在对象被释放之前获取控制权,可以定义DESTROY()方法。DESTROY()在对象将释放前被调用,使你可以做一些清理工作。DESTROY()函数不自动调用其它DESTROY()函数,Perl不做内置的析构工作。如果构造函数从基类多次bless,DESTROY()可能需要调用其它类的DESTROY()函数。当一个对象被释放时,其内含的所有对象引用自动释放、销毁。<BR> 一般来说,不需要定义DESTROY()函数,如果需要,其形式如下:<BR></P>
<BLOCKQUOTE>
<P>sub DESTROY {<BR>#<BR># Add code here.<BR>#<BR>} </P></BLOCKQUOTE>
<P> 因为多种目的,Perl使用了简单的、基于引用的垃圾回收系统。任何对象的引用数目必须大于零,否则该对象的内存就被释放。当程序退出时,Perl的一个彻底的查找并销毁函数进行垃圾回收,进程中的一切被简单地删除。在UNIX类的系统中,这像是多余的,但在内嵌式系统或多线程环境中这确实很必要。<BR><A
name=10>十、继承</A><BR> 类方法通过@ISA数组继承,变量的继承必须明确设定。下例创建两个类Bean.pm和Coffee.pm,其中Coffee.pm继承Bean.pm的一些功能。此例演示如何从基类(或称超类)继承实例变量,其方法为调用基类的构造函数并把自己的实例变量加到新对象中。<BR> Bean.pm代码如下:<BR></P>
<BLOCKQUOTE>
<P>package Bean;<BR>require Exporter;<BR>@ISA = qw(Exporter);<BR>@EXPORT
= qw(setBeanType);<BR><BR>sub new {<BR> my $type =
shift;<BR> my $this = {};<BR> $this->{'Bean'} =
'Colombian';<BR> bless $this, $type;<BR> return
$this;<BR>}<BR><BR>#<BR># This subroutine sets the class name<BR>sub
setBeanType{<BR> my ($class, $name) = @_;<BR>
$class->{'Bean'} = $name;<BR> print "Set bean to $name
\n";<BR>}<BR>1; </P></BLOCKQUOTE>
<P> 此类中,用$this变量设置一个匿名哈希表,将'Bean'类型设为'Colombian'。方法setBeanType()用于改变'Bean'类型,它使用$class引用获得对对象哈希表的访问。<BR> Coffee.pm代码如下:<BR></P>
<BLOCKQUOTE>
<P>1 #<BR>2 # The Coffee.pm file to illustrate
inheritance.<BR>3 #<BR>4 package Coffee;<BR>5 require
Exporter;<BR>6 require Bean;<BR>7 @ISA = qw(Exporter,
Bean);<BR>8 @EXPORT = qw(setImports, declareMain,
closeMain);<BR>9 #<BR>10 # set item<BR>11 #<BR>12 sub
setCoffeeType{<BR>13 my ($class,$name) = @_;<BR>14
$class->{'Coffee'} = $name;<BR>15 print "Set coffee type to
$name \n";<BR>16 }<BR>17 #<BR>18 # constructor<BR>19 #<BR>20 sub
new {<BR>21 my $type = shift;<BR>22 my $this =
Bean->new(); ##### <- LOOK HERE!!! ####<BR>23
$this->{'Coffee'} = 'Instant'; # unless told otherwise<BR>24
bless $this, $type;<BR>25 return $this;<BR>26 }<BR>27 1;
</P></BLOCKQUOTE>
<P> 第6行的require
Bean;语句包含了Bean.pm文件和所有相关函数,方法setCoffeeType()用于设置局域变量$class->{'Coffee'}的值。在构造函数new()中,$this指向Bean.pm返回的匿名哈希表的指针,而不是在本地创建一个,下面两个语句分别为创建不同的哈希表从而与Bean.pm构造函数创建的哈希表无关的情况和继承的情况:<BR> my
$this = {}; #非继承<BR> my $this =
$theSuperClass->new();
#继承<BR> 下面代码演示如何调用继承的方法:<BR></P>
<BLOCKQUOTE>
<P>1 #!/usr/bin/perl<BR>2 push (@INC,'pwd');<BR>3 use
Coffee;<BR>4 $cup = new Coffee;<BR>5 print "\n
-------------------- Initial values ------------ \n";<BR>6 print
"Coffee: $cup->{'Coffee'} \n";<BR>7 print "Bean:
$cup->{'Bean'} \n";<BR>8 print "\n -------------------- Change
Bean Type ---------- \n";<BR>9
$cup->setBeanType('Mixed');<BR>10 print "Bean Type is now
$cup->{'Bean'} \n";<BR>11 print "\n ------------------ Change Coffee
Type ---------- \n";<BR>12 $cup->setCoffeeType('Instant');<BR>13
print "Type of coffee: $cup->{'Coffee'} \n"; </P></BLOCKQUOTE>
<P> 该代码的结果输出如下:<BR></P>
<BLOCKQUOTE>
<P>-------------------- Initial values ------------<BR>Coffee:
Instant<BR>Bean: Colombian<BR>-------------------- Change Bean Type
----------<BR>Set bean to Mixed<BR>Bean Type is now Mixed
<BR>------------------ Change Coffee Type ----------<BR>Set coffee type
to Instant<BR>Type of coffee: Instant </P></BLOCKQUOTE>
<P> 上述代码中,先输出对象创建时哈希表中索引为'Bean'和'Coffee'的值,然后调用各成员函数改变值后再输出。<BR> 方法可以有多个参数,现在向Coffee.pm模块增加函数makeCup(),代码如下:<BR></P>
<BLOCKQUOTE>
<P>sub makeCup {<BR> my ($class, $cream, $sugar, $dope) =
@_;<BR> print "\n================================== \n";
<BR> print "Making a cup \n";<BR> print "Add cream \n" if
($cream);<BR> print "Add $sugar sugar cubes\n" if
($sugar);<BR> print "Making some really addictive coffee ;-) \n"
if ($dope);<BR> print "==================================
\n";<BR>} </P></BLOCKQUOTE>
<P> 此函数可有三个参数,不同数目、值的参数产生不同的结果,例如:<BR></P>
<BLOCKQUOTE>
<P>1 #!/usr/bin/perl<BR>2 push (@INC,'pwd');<BR>3 use
Coffee;<BR>4 $cup = new Coffee;<BR>5 #<BR>6 # With no
parameters<BR>7 #<BR>8 print "\n Calling with no parameters:
\n";<BR>9 $cup->makeCup;<BR>10 #<BR>11 # With one
parameter<BR>12 #<BR>13 print "\n Calling with one parameter: \n";<BR>14
$cup->makeCup('1');<BR>15 #<BR>16 # With two parameters<BR>17 #<BR>18
print "\n Calling with two parameters: \n";<BR>19
$cup->makeCup(1,'2');<BR>20 #<BR>21 # With all three parameters<BR>22
#<BR>23 print "\n Calling with three parameters: \n";<BR>24
$cup->makeCup('1',3,'1'); </P></BLOCKQUOTE>
<P> 其结果输出如下:<BR></P>
<BLOCKQUOTE>
<P>Calling with no
parameters:<BR>==================================<BR>Making a
cup<BR>==================================<BR>Calling with one
parameter:<BR>==================================<BR>Making a cup<BR>Add
cream<BR>==================================<BR>Calling with two
parameters:<BR>==================================<BR>Making a cup<BR>Add
cream<BR>Add 2 sugar
cubes<BR>==================================<BR>Calling with three
parameters:<BR>==================================<BR>Making a cup<BR>Add
cream<BR>Add 3 sugar cubes<BR>Making some really addictive coffee
;-)<BR>================================== </P></BLOCKQUOTE>
<P> 在此例中,函数makeCup()的参数既可为字符串也可为整数,处理结果相同,你也可以把这两种类型的数据处理区分开。在对参数的处理中,可以设置缺省的值,也可以根据实际输入参数值的个数给予不同处理。<BR><BR><A
name=11>十一、子类方法的重载</A><BR> 继承的好处在于可以获得基类输出的方法的功能,而有时需要对基类的方法重载以获得更具体或不同的功能。下面在Bean.pm类中加入方法printType(),代码如下:<BR></P>
<BLOCKQUOTE>
<P>sub printType {<BR> my $class = shift @_;<BR> print "The
type of Bean is $class->{'Bean'} \n";<BR>} </P></BLOCKQUOTE>
<P> 然后更新其@EXPORT数组来输出:<BR> @EXPORT
= qw ( setBeanType , printType
);<BR> 现在来调用函数printType(),有三种调用方法:<BR></P>
<BLOCKQUOTE>
<P>$cup->Coffee::printType();<BR>$cup->printType();<BR>$cup->Bean::printType();
</P></BLOCKQUOTE>
<P> 输出分别如下:<BR></P>
<BLOCKQUOTE>
<P>The type of Bean is Mixed<BR>The type of Bean is Mixed<BR>The type of
Bean is Mixed </P></BLOCKQUOTE>
<P> 为什么都一样呢?因为在子类中没有定义函数printType(),所以实际均调用了基类中的方法。如果想使子类有其自己的printType()函数,必须在Coffee.pm类中加以定义:<BR></P>
<BLOCKQUOTE>
<P>#<BR># This routine prints the type of
$class->{'Coffee'}<BR>#<BR>sub printType {<BR> my $class =
shift @_;<BR> print "The type of Coffee is $class->{'Coffee'}
\n";<BR>} </P></BLOCKQUOTE>
<P> 然后更新其@EXPORT数组:<BR> @EXPORT
= qw(setImports, declareMain, closeMain,
printType);<BR> 现在输出结果变成了:<BR></P>
<BLOCKQUOTE>
<P>The type of Coffee is Instant<BR>The type of Coffee is Instant<BR>The
type of Bean is Mixed </P></BLOCKQUOTE>
<P> 现在只有当给定了Bean::时才调用基类的方法,否则直接调用子类的方法。<BR> 那么如果不知道基类名该如何调用基类方法呢?方法是使用伪类保留字SUPER::。在类方法内使用语法如:$this->SUPER::function(...argument
list...);
,它将从@ISA列表中寻找。刚才的语句用SUPER::替换Bean::可以写为$cup->SUPER::printType();
,其结果输出相同,为:<BR></P>
<BLOCKQUOTE>
<P>The type of Bean is Mixed</P></BLOCKQUOTE>
<P><BR><A name=12></A><FONT
color=#003333>十二、Perl类和对象的一些注释</FONT><BR> OOP的最大好处就是代码重用。OOP用数据封装来隐藏一些复杂的代码,Perl的包和模块通过my函数提供数据封装功能,但是Perl并不保证子类一定不会直接访问基类的变量,这确实减少了数据封装的好处,虽然这种动作是可以做到的,但却是个很坏的编程风格。<BR>注意:
</P>
<BLOCKQUOTE>
<P>1、一定要通过方法来访问类变量。<BR>2、一定不要从模块外部直接访问类变量。</P></BLOCKQUOTE>
<P> 当编写包时,应该保证方法所需的条件已具备或通过参数传递给它。在包内部,应保证对全局变量的访问只用通过方法传递的引用来访问。对于方法要使用的静态或全局数据,应该在基类中用local()来定义,子类通过调用基类来获取。有时,子类可能需要改变这种数据,这时,基类可能就不知道怎样去寻找新的数据,因此,这时最好定义对该数据的引用,子类和基类都通过引用来改变该数据。<BR> 最后,你将看到如下方式来使用对象和类:<BR> use
coffee::Bean;<BR> 这句语句的含义是“在@INC数组所有目录的Coffee子目录来寻找Bean.pm”。如果把Bean.pm移到./Coffee目录,上面的例子将用这一use语句来工作。这样的好处是有条理地组织类的代码。再如,下面的语句:<BR> use
Another::Sub::Menu;<BR> 意味着如下子目录树:<BR> ./Another/Sub/Menu.pm
</P></DIV></DIV></TD></TR></TBODY></TABLE>
<DIV align=center></DIV>
<DIV align=center><BR></DIV>
<DIV align=center><SPAN class=myFont><A
href="http://www.sun126.com/perl5/perl5-12.htm">上页</A> <A
href="http://www.sun126.com/perl5/perl5-14.htm">下页</A> <A
href="http://www.sun126.com/perl5/perl5index.htm">回目录</A> <A
href="http://www.sun126.com/perl5/perl5-13.htm#a"><FONT face="Arial, 宋体">Go
Top</FONT></A></SPAN><BR><BR></DIV>
<TABLE height=50 cellSpacing=0 cellPadding=0 width="100%" bgColor=#000000
border=0>
<TBODY>
<TR>
<TD bgColor=#cccc99 height=4>
<DIV align=center><IMG height=4 src="" width=4></DIV></TD></TR>
<TR>
<TD height=50>
<DIV align=center><FONT class=myfont size=2><SPAN class=myfont><FONT
color=#99cc99><A href="http://www.sun126.com/bbs/ccb/index.cgi"><FONT
color=#99cc99>中国CCB论坛</FONT></A> 整理 麻辣
2003.7.10</FONT></SPAN></FONT><FONT class=myfont color=#99cc99
size=2><SPAN class=myfont><FONT
color=#99cc66><BR></FONT></SPAN></FONT><SPAN class=myfont><FONT
class=myfont><SPAN class=myfont><FONT face="Arial, Helvetica, sans-serif"
color=#99cc99>© 2000
http://www.sun126.com</FONT></SPAN></FONT></SPAN></DIV></TD></TR></TBODY></TABLE></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -