⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch5.htm

📁 《Perl 5 Unreleased》
💻 HTM
📖 第 1 页 / 共 5 页
字号:
you would use the following statement:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">@EXPORT(declareMain, closeMain);</FONT></TT>

</BLOCKQUOTE>

<P>

Inheritance in a Perl class is accomplished via the <TT><FONT FACE="Courier">@ISA</FONT></TT>

array. The <TT><FONT FACE="Courier">@ISA</FONT></TT> array does

not have to be defined in every package; however, when it is defined,

Perl treats it as a special array of directory names. This is

akin to the <TT><FONT FACE="Courier">@Inc</FONT></TT> array where

directories are searched for files to include. In the case of

the <TT><FONT FACE="Courier">@ISA</FONT></TT> array, the paths

define the classes (packages) and where to look for other class

packages, if a method is not found in the current package. Thus,

the <TT><FONT FACE="Courier">@ISA</FONT></TT> array contains the

names of the base classes from which the current class inherits.

The search is done in the order in which the classes are listed

in the <TT><FONT FACE="Courier">@ISA</FONT></TT> arrays.

<P>

All methods called by a class do have to belong to the same class

or to the base classes defined in the <TT><FONT FACE="Courier">@ISA</FONT></TT>

array. If a method isn't found in <TT><FONT FACE="Courier">@ISA</FONT></TT>

array, Perl looks for an <TT><FONT FACE="Courier">AUTOLOAD()</FONT></TT>

routine. This routine is defined as <TT><FONT FACE="Courier">sub</FONT></TT>

in the current package and is optional. To use the <TT><FONT FACE="Courier">AUTOLOAD</FONT></TT>

function, you have to use the <TT><FONT FACE="Courier">autoload.pm</FONT></TT>

package with the <TT><FONT FACE="Courier">use Autoload</FONT></TT>;

statement. The <TT><FONT FACE="Courier">AUTOLOAD</FONT></TT> function

tries to load the called function from the installed Perl libraries.

If the <TT><FONT FACE="Courier">AUTOLOAD</FONT></TT> call also

fails, Perl makes one final try at the <TT><FONT FACE="Courier">UNIVERSAL</FONT></TT>

class, which is the catch-all for all methods not defined elsewhere.

Perl will generate an error about unresolved functions if this

step also fails.

<P>

Here are some simple rules when exporting methods. First, export

only those functions that you have to. Do not export every function

in your module because you will be increasing the likelihood of

conflicts with a program that is using your module. Use the <TT><FONT FACE="Courier">@EXPORT_OK</FONT></TT>

array instead of the <TT><FONT FACE="Courier">@EXPORT</FONT></TT>

array if you feel that the names of your methods may clash with

those in an application. Choosing long, descriptive names for

functions may help eliminate problems with synonymous variable

names. 

<P>

Second, if you are going to have multiple versions of your module,

consider setting a variable called <TT><FONT FACE="Courier">$VERSION</FONT></TT>

in your module to a numeric string; for example, <TT><FONT FACE="Courier">&quot;2.11&quot;</FONT></TT>

or something. This version number will be exported for you automatically

and can be used with the <TT><FONT FACE="Courier">require</FONT></TT>

statement. Remember to use two digits for all integers in the

version numbers because <TT><FONT FACE="Courier">&quot;1.10&quot;</FONT></TT>

is interpreted lower than <TT><FONT FACE="Courier">&quot;1.9&quot;</FONT></TT>

but higher than <TT><FONT FACE="Courier">&quot;1.09&quot;</FONT></TT>.

You will see some modules or programs with a statement of the

following form: 

<BLOCKQUOTE>

<TT><FONT FACE="Courier">require 5.001; </FONT></TT>

</BLOCKQUOTE>

<P>

The statement above indicates that Perl version 5.001 or greater

is required. The same analogy can be used for your module with

a call to a function called<TT><FONT FACE="Courier"> require_version</FONT></TT>

of the following form: 

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$moduleName-&gt;require_version($value);</FONT></TT>

</BLOCKQUOTE>

<P>

A returned value of <TT><FONT FACE="Courier">true</FONT></TT>

will indicate that it's okay to proceed. A returned value of <TT><FONT FACE="Courier">false</FONT></TT>

will indicate that the version number of the module is less than

what is specified in the <TT><FONT FACE="Courier">$value</FONT></TT>.

<H2><A NAME="InvokingMethods"><FONT SIZE=5 COLOR=#FF0000>Invoking

Methods</FONT></A></H2>

<P>

There are two ways to invoke a method for an object: one via a

reference to an object (virtual) and the other via explicitly

referring to the class name (static). A method has to be exported

for you to be able to call it. Let's add a few more methods to

the <TT><FONT FACE="Courier">Cocoa</FONT></TT> class to get the

file to look like the one shown in Listing 5.10.

<HR>

<BLOCKQUOTE>

<B>Listing 5.10. Adding methods to the </B><TT><B><FONT FACE="Courier">Cocoa</FONT></B></TT><B>

class.<BR>

</B>

</BLOCKQUOTE>

<BLOCKQUOTE>

<TT><FONT FACE="Courier">&nbsp;1 package Cocoa;<BR>

&nbsp;2 require Exporter;<BR>

&nbsp;3 <BR>

&nbsp;4 @ISA = qw(Exporter);<BR>

&nbsp;5 @EXPORT = qw(setImports,

declareMain, closeMain);<BR>

&nbsp;6 <BR>

&nbsp;7 #<BR>

&nbsp;8 # This routine creates the references for imports in Java

functions<BR>

&nbsp;9 #<BR>

10 sub setImports{<BR>

11&nbsp;&nbsp;&nbsp;&nbsp; my $class = shift @_;<BR>

12&nbsp;&nbsp;&nbsp;&nbsp; my @names = @_;<BR>

13 <BR>

14&nbsp;&nbsp;&nbsp;&nbsp; foreach (@names) {<BR>

15&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print &quot;import &quot;

.&nbsp;&nbsp;$_ . &quot;;\n&quot;;<BR>

16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>

17&nbsp;&nbsp;&nbsp;&nbsp; }<BR>

18 <BR>

19 #<BR>

20 # This routine declares the main function in a Java script

<BR>

21 #<BR>

22 sub declareMain{<BR>

23&nbsp;&nbsp;&nbsp;&nbsp; my $class = shift @_;<BR>

24&nbsp;&nbsp;&nbsp;&nbsp; my ( $name, $extends, $implements)

= @_;<BR>

25 <BR>

26&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print &quot;\n public class

$name&quot;;<BR>

27&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($extends) {<BR>

28&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

print &quot; extends &quot; . $extends;<BR>

29&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>

30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($implements) {<BR>

31&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

print &quot; implements &quot; . $implements;<BR>

32&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>

33&nbsp;&nbsp;&nbsp;&nbsp;print &quot; { \n&quot;;<BR>

34 }<BR>

35 <BR>

36 #<BR>

37 # This routine declares the main function in a Java script

<BR>

38 #<BR>

39 sub closeMain{<BR>

40&nbsp;&nbsp;&nbsp;&nbsp;print &quot;} \n&quot;;<BR>

41 }<BR>

42 <BR>

43 #<BR>

44 #&nbsp;&nbsp;This subroutine creates the header for the file.

<BR>

45 #<BR>

46 sub new {<BR>

47&nbsp;&nbsp;&nbsp;&nbsp; my $this = {};<BR>

48&nbsp;&nbsp;&nbsp;&nbsp; print &quot;\n /* \n ** Created by

Cocoa.pm \n ** Use at own risk \n */ \n&quot;;<BR>

49&nbsp;&nbsp;&nbsp;&nbsp; bless $this;<BR>

50&nbsp;&nbsp;&nbsp;&nbsp; return $this;<BR>

51&nbsp;&nbsp;&nbsp;&nbsp; }<BR>

52 <BR>

53 1;</FONT></TT>

</BLOCKQUOTE>

<HR>

<P>

Now let's write a simple Perl script to use the methods for this

class. Because you can only start and close the header, let's

see how the code for a script to create a skeleton Java applet

source looks. (See Listing 5.11.)

<HR>

<BLOCKQUOTE>

<B>Listing 5.11. Using the methods just added in Listing 5.10.

<BR>

</B>

</BLOCKQUOTE>

<BLOCKQUOTE>

<TT><FONT FACE="Courier">1 #!/usr/bin/perl<BR>

2 <BR>

3 use Cocoa;<BR>

4 <BR>

5 $cup = new Cocoa;<BR>

6 <BR>

7 $cup-&gt;setImports( 'java.io.InputStream', 'java.net.*');<BR>

8 $cup-&gt;declareMain( &quot;Msg&quot; , &quot;java.applet.Applet&quot;,

&quot;Runnable&quot;);<BR>

9 $cup-&gt;closeMain();</FONT></TT>

</BLOCKQUOTE>

<HR>

<P>

What we are doing in this script is generating code for a Java

applet called <TT><FONT FACE="Courier">Msg</FONT></TT>, which

extends the <TT><FONT FACE="Courier">java.applet.Applet</FONT></TT>

applet and implements functions that can be run. The function

is called with a function <TT><FONT FACE="Courier">$cup-&gt;...</FONT></TT>

call. Lines 7 through 9 could be rewritten as functions, like

this:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">Cocoa::setImports($cup,  'java.io.InputStream',

'java.net.*');<BR>

Cocoa::declareMain($cup, &quot;Msg&quot; , &quot;java.applet.Applet&quot;,

&quot;Runnable&quot;);<BR>

Cocoa::closeMain($cup);</FONT></TT>

</BLOCKQUOTE>

<P>

This type of equivalence was shown in a previous section, &quot;Blessing

a Constructor.&quot; In both cases, the first parameter is the

reference to the object itself. Running this test script generates

the following output:

<BLOCKQUOTE>

<TT><FONT FACE="Courier"> /*<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>

}</FONT></TT>

</BLOCKQUOTE>

<P>

There are a couple of points to note when calling the methods.

If you have any arguments to a method, use parentheses if you

are using the method <TT><FONT FACE="Courier">-&gt;</FONT></TT>

(also known as indirect). The parentheses are required to include

all the arguments with this statement:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$cup-&gt;setImports( 'java.io.InputStream',

'java.net.*');</FONT></TT>

</BLOCKQUOTE>

<P>

However, this statement:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">Cocoa::setImports($cup,  'java.io.InputStream',

'java.net.*');</FONT></TT>

</BLOCKQUOTE>

<P>

can also be rewritten without parentheses.

<BLOCKQUOTE>

<TT><FONT FACE="Courier">Cocoa::setImports $cup,  'java.io.InputStream',

'java.net.*' ;</FONT></TT>

</BLOCKQUOTE>

<P>

The choice is really yours as to how you intend to make your code

readable for other programmers. Use parentheses if you feel that

the code will be more readable.

<H2><A NAME="Overrides"><FONT SIZE=5 COLOR=#FF0000>Overrides</FONT></A>

</H2>

<P>

There are times when you'll want to specify which class' method

to use, such as when the same-named method is specified in two

different classes. For example, if the function <TT><FONT FACE="Courier">grind</FONT></TT>

is defined in both <TT><FONT FACE="Courier">Espresso</FONT></TT>

and <TT><FONT FACE="Courier">Qava</FONT></TT> classes, you can

specify which class' function to use with the use of the <TT><FONT FACE="Courier">::</FONT></TT>

operator. These two calls:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$mess = Espresso::grind(&quot;whole&quot;,&quot;lotta&quot;,&quot;bags&quot;);

<BR>

Espresso::grind($mess, &quot;whole&quot;,&quot;lotta&quot;,&quot;bags&quot;);</FONT></TT>

</BLOCKQUOTE>

<P>

use the call in <TT><FONT FACE="Courier">Espresso</FONT></TT>,

whereas the following calls use the <TT><FONT FACE="Courier">grind()</FONT></TT>

function in the <TT><FONT FACE="Courier">Qava</FONT></TT> class:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$mess = Qava::grind(&quot;whole&quot;,&quot;lotta&quot;,&quot;bags&quot;);

<BR>

Qava::grind($mess, &quot;whole&quot;,&quot;lotta&quot;,&quot;bags&quot;);</FONT></TT>

</BLOCKQUOTE>

<P>

Sometimes you want to call a method based on some action that

the program you are writing has already taken. In other words,

you want to use the <TT><FONT FACE="Courier">Qava</FONT></TT>

method for a certain condition and the <TT><FONT FACE="Courier">Espresso</FONT></TT>

method for another. In this case, you can use symbolic references

to make the call to the required function. This is illustrated

in the following example:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$method = $local ? &quot;Qava::&quot;

: &quot;Espresso::&quot;;<BR>

$cup-&gt;{$method}grind(@args);</FONT></TT>

</BLOCKQUOTE>

<H2><A NAME="Destructors"><FONT SIZE=5 COLOR=#FF0000>Destructors</FONT></A>

</H2>

<P>

Perl tracks the number of links to objects. When the last reference

to an object goes away, the object is automatically destroyed.

This destruction of an object may occur after your code stops

and the script is about to exit. For global variables, the destruction

happens after the last line in your code executes.

<P>

If you want to capture control just before the object is freed,

you can define a <TT><FONT FACE="Courier">DESTROY()</FONT></TT>

method in your class. Note the use of all capitals in the name.

The <TT><FONT FACE="Courier">DESTROY()</FONT></TT> method is called

just before the object is released, allowing you to do any cleanup.

The <TT><FONT FACE="Courier">DESTROY()</FONT></TT> function does

not call other <TT><FONT FACE="Courier">DESTROY()</FONT></TT>

functions. Perl doesn't do nested destruction for you. If your

constructor reblessed a reference from one of your base classes,

your <TT><FONT FACE="Courier">DESTROY()</FONT></TT> may need to

call <TT><FONT FACE="Courier">DESTROY()</FONT></TT> for any base

classes. All object references that are contained in a given object

are freed and destroyed automatically when the current object

is freed.

<P>

Normally, you don't have to define a <TT><FONT FACE="Courier">DESTROY</FONT></TT>

function. However, when you do need it, its form is as follows:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">sub DESTROY {<BR>

#<BR>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -