?? perl13.htm
字號:
<blockquote>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;</blockquote>
第6行的require Bean;語句包含了Bean.pm文件和所有相關函數,方法setCoffeeType()用于設置局域變量$class->{'Coffee'}的值。在構造函數new()中,$this指向Bean.pm返回的匿名哈希表的指針,而不是在本地創建一個,下面兩個語句分別為創建不同的哈希表從而與Bean.pm構造函數創建的哈希表無關的情況和繼承的情況:<br>
my $this = {}; #非繼承<br>
my $this = $theSuperClass->new(); #繼承<br>
下面代碼演示如何調用繼承的方法:<br>
<blockquote>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";</blockquote>
該代碼的結果輸出如下:<br>
<blockquote>-------------------- 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</blockquote>
上述代碼中,先輸出對象創建時哈希表中索引為'Bean'和'Coffee'的值,然后調用各成員函數改變值后再輸出。<br>
方法可以有多個參數,現在向Coffee.pm模塊增加函數makeCup(),代碼如下:<br>
<blockquote>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>
}</blockquote>
此函數可有三個參數,不同數目、值的參數產生不同的結果,例如:<br>
<blockquote>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');</blockquote>
其結果輸出如下:<br>
<blockquote>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>
==================================</blockquote>
在此例中,函數makeCup()的參數既可為字符串也可為整數,處理結果相同,你也可以把這兩種類型的數據處理區分開。在對參數的處理中,可以設置缺省的值,也可以根據實際輸入參數值的個數給予不同處理。<br>
<a name=11>十一、子類方法的重載</a><br>
繼承的好處在于可以獲得基類輸出的方法的功能,而有時需要對基類的方法重載以獲得更具體或不同的功能。下面在Bean.pm類中加入方法printType(),代碼如下:<br>
<blockquote>sub printType {<br>
my $class = shift @_;<br>
print "The type of Bean is $class->{'Bean'} \n";<br>
}</blockquote>
然后更新其@EXPORT數組來輸出:<br>
@EXPORT = qw ( setBeanType , printType );<br>
現在來調用函數printType(),有三種調用方法:<br>
<blockquote>$cup->Coffee::printType();<br>
$cup->printType();<br>
$cup->Bean::printType();</blockquote>
輸出分別如下:<br>
<blockquote>The type of Bean is Mixed<br>
The type of Bean is Mixed<br>
The type of Bean is Mixed</blockquote>
為什么都一樣呢?因為在子類中沒有定義函數printType(),所以實際均調用了基類中的方法。如果想使子類有其自己的printType()函數,必須在Coffee.pm類中加以定義:<br>
<blockquote>#<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>
}</blockquote>
然后更新其@EXPORT數組:<br>
@EXPORT = qw(setImports, declareMain, closeMain,
printType);<br>
現在輸出結果變成了:<br>
<blockquote>The type of Coffee is Instant<br>
The type of Coffee is Instant<br>
The type of Bean is Mixed</blockquote>
現在只有當給定了Bean::時才調用基類的方法,否則直接調用子類的方法。<br>
那么如果不知道基類名該如何調用基類方法呢?方法是使用偽類保留字SUPER::。在類方法內使用語法如:$this->SUPER::function(...argument
list...); ,它將從@ISA列表中尋找。剛才的語句用SUPER::替換Bean::可以寫為$cup->SUPER::printType();
,其結果輸出相同,為:<br>
<blockquote>The type of Bean is Mixed</blockquote>
十二、Perl類和對象的一些注釋<br>
OOP的最大好處就是代碼重用。OOP用數據封裝來隱藏一些復雜的代碼,Perl的包和模塊通過my函數提供數據封裝功能,但是Perl并不保證子類一定不會直接訪問基類的變量,這確實減少了數據封裝的好處,雖然這種動作是可以做到的,但卻是個很壞的編程風格。<br>
注意:
<blockquote>1、一定要通過方法來訪問類變量。<br>
2、一定不要從模塊外部直接訪問類變量。</blockquote>
當編寫包時,應該保證方法所需的條件已具備或通過參數傳遞給它。在包內部,應保證對全局變量的訪問只用通過方法傳遞的引用來訪問。對于方法要使用的靜態或全局數據,應該在基類中用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<br>
<p align=center><a href=perl12.htm>上一章</a> <a href=perl14.htm>下一章</a>
<a href=index.htm>目錄</a></p>
<p align=center> </p>
<!-- #EndEditable --></td>
</tr>
</table>
</td></tr></table></body><!-- #EndTemplate --></html>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -