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

📄 ch5.htm

📁 《Perl 5 Unreleased》
💻 HTM
📖 第 1 页 / 共 5 页
字号:
<TT><FONT FACE="Courier">&nbsp;Calling&nbsp;&nbsp;with no parameters:

<BR>

<BR>

==================================<BR>

Making a cup<BR>

==================================<BR>

<BR>

&nbsp;Calling&nbsp;&nbsp;with

one parameter:<BR>

<BR>

==================================<BR>

Making a cup<BR>

Add cream<BR>

==================================<BR>

<BR>

&nbsp;Calling&nbsp;&nbsp;with two parameters:<BR>

<BR>

==================================<BR>

Making a cup<BR>

Add cream<BR>

Add 2 sugar cubes<BR>

==================================<BR>

<BR>

&nbsp;Calling with three parameters:<BR>

<BR>

==================================<BR>

Making a cup<BR>

Add cream<BR>

Add 3 sugar cubes<BR>

Making some really addictive coffee ;-)<BR>

==================================</FONT></TT>

</BLOCKQUOTE>

<P>

In any event, you can have default values in the function to set

if the expected parameter is not passed in. Thus, the behavior

of the method can be different depending on the number of arguments

you pass into it.

<H2><A NAME="OverridingMethods"><FONT SIZE=5 COLOR=#FF0000>Overriding

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

<P>

Inheriting functionality from another class is beneficial in that

you can get all the exported functionality of the base class in

your new class. To see an example of how this works, let's add

a function called <TT><FONT FACE="Courier">printType</FONT></TT>

in the <TT><FONT FACE="Courier">Bean.pm</FONT></TT> class. Here's

the subroutine:

<BLOCKQUOTE>

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

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

&nbsp;&nbsp;&nbsp;&nbsp;print &quot;The type of Bean is $class-&gt;{'Bean'}

\n&quot;;<BR>

}</FONT></TT>

</BLOCKQUOTE>

<P>

Do not forget to update the <TT><FONT FACE="Courier">@EXPORT</FONT></TT>

array by adding the name of the function to export. The new statement

should look like this:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">@EXPORT = qw(setBeanType, printType,

printType);</FONT></TT>

</BLOCKQUOTE>

<P>

Next, call the <TT><FONT FACE="Courier">printType</FONT></TT>

function. The following three lines show three ways to call this

function:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$cup-&gt;Coffee::printType();<BR>

$cup-&gt;printType();<BR>

$cup-&gt;Bean::printType();</FONT></TT>

</BLOCKQUOTE>

<P>

The output from all three lines is the same:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">The type of Bean is Mixed<BR>

The type of Bean is Mixed<BR>

The type of Bean is Mixed</FONT></TT>

</BLOCKQUOTE>

<P>

Why is this so? Because there is no <TT><FONT FACE="Courier">printType()</FONT></TT>

function in the inheriting class, the <TT><FONT FACE="Courier">printType()</FONT></TT>

function in the base class is used instead. Naturally, if you

want your own class to have its own <TT><FONT FACE="Courier">printType</FONT></TT>

function, you would define its own <TT><FONT FACE="Courier">printType</FONT></TT>

function.

<P>

In the <TT><FONT FACE="Courier">Coffee.pm</FONT></TT> file, you

would add the following lines to the end of the file:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">#<BR>

# This routine prints the type of $class-&gt;{'Coffee'}<BR>

#<BR>

sub printType {<BR>

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

&nbsp;&nbsp;&nbsp;&nbsp;print &quot;The type of Coffee is $class-&gt;{'Coffee'}

\n&quot;;<BR>

}</FONT></TT>

</BLOCKQUOTE>

<P>

<TT><FONT FACE="Courier">@EXPORT</FONT></TT> would also have to

be modified to work with this function:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">@EXPORT = qw(setImports, declareMain,

closeMain, printType);</FONT></TT>

</BLOCKQUOTE>

<P>

The output from the three lines now looks like this:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">The type of Coffee is Instant<BR>

The type of Coffee is Instant<BR>

The type of Bean is Mixed</FONT></TT>

</BLOCKQUOTE>

<P>

Now the base class function is called only when the <TT><FONT FACE="Courier">Bean::</FONT></TT>

override is given. In the other cases, only the inherited class

function is called.

<P>

What if you do not know what the base class name is or even where

the name is defined. In this case, you can use the <TT><FONT FACE="Courier">SUPER::</FONT></TT>

pseudoclass reserved word. Using the <TT><FONT FACE="Courier">SUPER::</FONT></TT>

override allows you to call an overridden superclass method without

actually knowing where that method is defined. The <TT><FONT FACE="Courier">SUPER::</FONT></TT>

construct is meaningful only within the class.

<P>

If you're trying to control where the method search begins and

you're executing in the class itself, you can use the <TT><FONT FACE="Courier">SUPER::</FONT></TT>

pseudoclass, which says to start looking in your base class's

<TT><FONT FACE="Courier">@ISA</FONT></TT> list without having

to explicitly name it.

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$this-&gt;SUPER::function( ... argument

list ... );</FONT></TT>

</BLOCKQUOTE>

<P>

Therefore, instead of <TT><FONT FACE="Courier">Bean::</FONT></TT>,

you can use <TT><FONT FACE="Courier">SUPER::</FONT></TT>. The

call to the function <TT><FONT FACE="Courier">printType()</FONT></TT>

becomes this:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$cup-&gt;SUPER::printType();</FONT></TT>

</BLOCKQUOTE>

<P>

Here's the output:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">The type of Bean is Mixed</FONT></TT>

</BLOCKQUOTE>

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

Few Comments About Classes and Objects in Perl</FONT></A></H2>

<P>

One advertised strength of object-oriented languages is the ease

with which new code can use old code. Packages and modules in

Perl provide a great deal of data encapsulation. You are never

really guaranteeing that a class inheriting your code will not

attempt to access your class variables directly. They can if they

really want to. However, this type of procedure is considered

bad practice, and shame on you if you do it.

<P>

When writing a package, you should ensure that everything a method

needs is available via the object or is passed as a parameter

to the method. From within the package, access any global variables

only through references passed in via methods.

<P>

For static or global data to be used by the methods, you have

to define the context of the data in the base class using the

<TT><FONT FACE="Courier">local()</FONT></TT> construct. The subclass

will then call the base class to get the data for it. On occasion,

a subclass may want to override that data and replace it with

new data. When this happens, the superclass may not know how to

find the new copy of the data. In such cases, it's best to define

a reference to the data and then have all base classes and subclasses

modify the variable via that reference.

<P>

Finally, you'll see references to objects and classes like this:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">use Coffee::Bean;</FONT></TT>

</BLOCKQUOTE>

<P>

This code is interpreted to mean &quot;look for <TT><FONT FACE="Courier">Bean.pm</FONT></TT>

in the <TT><FONT FACE="Courier">Coffee</FONT></TT> subdirectory

in all the directories in the <TT><FONT FACE="Courier">@Inc</FONT></TT>

array.&quot; So, if you were to move <TT><FONT FACE="Courier">Bean.pm</FONT></TT>

into the <TT><FONT FACE="Courier">./Coffee</FONT></TT> directory,

all the previous examples would work with the new <TT><FONT FACE="Courier">use</FONT></TT>

statement. The advantage to this approach is that you have one

file for the parent class in one directory and the files for each

base class in their own  sub-directories. It helps keep code organized.

Therefore, to have a statement like this:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">use Another::Sub::Menu;</FONT></TT>

</BLOCKQUOTE>

<P>

you would see a directory subtree like this:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">./Another/Sub/Menu.pm</FONT></TT>

</BLOCKQUOTE>

<P>

Let's look at an example of a simple portfolio manager class called

<TT><FONT FACE="Courier">Invest.pm</FONT></TT>. There are two

subclasses derived from it that manage the type of funds. The

three files are shown in Listings 5.17, 5.18, and 5.19. The test

code to use these modules is shown in Listing 5.20. The <TT><FONT FACE="Courier">Invest.pm</FONT></TT>

file is placed in the current directory, and the <TT><FONT FACE="Courier">Stock.pm</FONT></TT>

and <TT><FONT FACE="Courier">Fund.pm</FONT></TT> files are placed

in the <TT><FONT FACE="Courier">Invest</FONT></TT> subdirectory.

<HR>

<BLOCKQUOTE>

<B>Listing 5.17. The </B><TT><B><FONT FACE="Courier">./Invest.pm</FONT></B></TT><B>

file.<BR>

</B>

</BLOCKQUOTE>

<BLOCKQUOTE>

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

&nbsp;2 <BR>

&nbsp;3 require Exporter;

<BR>

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

&nbsp;5 <BR>

&nbsp;6 =head1 NAME<BR>

&nbsp;7 <BR>

&nbsp;8 Letter - Sample module to simulate Bond behaviour<BR>

&nbsp;9 <BR>

10 =head1 SYNOPSIS<BR>

11 <BR>

12&nbsp;&nbsp;&nbsp;&nbsp; use Invest;<BR>

13&nbsp;&nbsp;&nbsp;&nbsp; use Invest::Fund;<BR>

14&nbsp;&nbsp;&nbsp;&nbsp; use Invest::Stock;<BR>

15 <BR>

16&nbsp;&nbsp;&nbsp;&nbsp; $port = new Invest::new();<BR>

17 <BR>

18&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$i1 = Invest::Fund('symbol'

=&gt; 'twcux');<BR>

19&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$i2 = Invest::Stock('symbol'

=&gt; 'INTC');<BR>

20&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$i3 = Invest::Stock('symbol'

=&gt; 'MSFT');<BR>

21 <BR>

22&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$port-&gt;Invest::AddItem($i1);

<BR>

23&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$port-&gt;Invest::AddItem($i2);

<BR>

24&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$port-&gt;Invest::AddItem($i3);

<BR>

25 <BR>

26&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$port-&gt;ShowPortfolio();

<BR>

27 <BR>

28 =head1 DESCRIPTION<BR>

29 <BR>

30 This module provides a short example of generating a letter

for a<BR>

31 friendly neighborbood loan shark.<BR>

32 <BR>

33 The code begins after the &quot;cut&quot; statement.<BR>

34 =cut<BR>

35 <BR>

36 @EXPORT = qw( new, AddItem, ShowPortfolio, PrintMe);<BR>

37 <BR>

38 @portfolio = ();<BR>

39 $portIndex = 0;<BR>

40 <BR>

41 sub Invest::new {<BR>

42&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $this

= shift;<BR>

43&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $class

= ref($this) || $this;<BR>

44&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $self

= {};<BR>

45&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bless

$self, $class;<BR>

46&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$portIndex = 0;<BR>

47 <BR>

48&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf &quot;\n Start portfolio&quot;;

<BR>

49&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return

$self;<BR>

50 }<BR>

51 <BR>

52 sub Invest::AddItem {<BR>

53&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my ($type,$stock) = @_;

<BR>

54&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$portfolio[$portIndex] =

$stock;<BR>

55&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$portIndex++;<BR>

56 }<BR>

57 <BR>

58 sub Invest::ShowPortfolio&nbsp;&nbsp;{<BR>

59&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $i;<BR>

60&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf &quot;\n Our Portfolio

is:&quot;;<BR>

61&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach $i (@portfolio)

{<BR>

62&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

print &quot;\n &quot;.&nbsp;&nbsp;$i-&gt;{'shares'} . &quot; shares

of &quot; . $i-&gt;{'symbol'};<BR>

63&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>

64&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print &quot;\n&quot;;<BR>

65 }<BR>

66 <BR>

67 sub PrintMe {<BR>

68&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $this = shift;<BR>

69&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print &quot;\n Class : $$this&quot;;

<BR>

70

⌨️ 快捷键说明

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