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

📄 ch14.htm

📁 prrl 5 programs codes in the book
💻 HTM
📖 第 1 页 / 共 5 页
字号:
Get the name of the class from the parameter array.<BR>

Assign the rest of the parameters to the </I><TT><I>%params</I></TT><I>

hash.<BR>

Call the constructor for the parent class, </I><TT><I>Inventory_item</I></TT><I>,

and assign the resulting object refereNCe to </I><TT><I>$self</I></TT><I>.

<BR>

Create an entry in the anonymous hash for the </I><TT><I>INK_COLOR</I></TT><I>

key.<BR>

Bless the anonymous hash so that </I><TT><I>ref()</I></TT><I>

will return </I><TT><I>Pen</I></TT><I>

and return a refereNCe to the anonymous hash.<BR>

Start the </I><TT><I>main</I></TT><I>

namespace.<BR>

Call the constructor for the </I><TT><I>Pen</I></TT><I>

class. Assign the object refereNCe to </I><TT><I>$item</I></TT><I>.

Note that an array with property-value pairs is passed to the

constructor.<BR>

Print the three property values to verify that the property initialization

worked.</I>

</BLOCKQUOTE>

<HR>

<BLOCKQUOTE>

<B>Listing 14.3&nbsp;&nbsp;14LST03.PL-How to Call the Constructor

of a Parent Class<BR>

</B>

</BLOCKQUOTE>

<BLOCKQUOTE>

<PRE>

package Inventory_item;

    sub new {

        my($class)  = shift;

        my(%params) = @_;

        bless {

            &quot;PART_NUM&quot;    =&gt; $params{&quot;PART_NUM&quot;},

            &quot;QTY_ON_HAND&quot; =&gt; $params{&quot;QTY_ON_HAND&quot;}

            }, $class;

    }



package Pen;

    @ISA = (Inventory_item);





 sub new {

        my($class) = shift;

        my(%params) = @_;

        my($self) = Inventory_item-&gt;new(@_);



        $self-&gt;{&quot;INK_COLOR&quot;} = $params{&quot;INK_COLOR&quot;};



        return(bless($self, $class));

    }



package main;

    $pen = Pen-&gt;new(

        &quot;PART_NUM&quot;    =&gt; &quot;12A-34&quot;,

        &quot;QTY_ON_HAND&quot; =&gt; 34,

        &quot;INK_COLOR&quot;   =&gt; &quot;blue&quot;);



    print(&quot;The part number is &quot; . %{$pen}-&gt;{'PART_NUM'}    . &quot;\n&quot;);

    print(&quot;The quantity is &quot;    . %{$pen}-&gt;{'QTY_ON_HAND'} . &quot;\n&quot;);

    print(&quot;The ink color is &quot;   . %{$pen}-&gt;{'INK_COLOR'}   . &quot;\n&quot;);

</PRE>

</BLOCKQUOTE>

<HR>

<P>

This program displays:

<BLOCKQUOTE>

<PRE>

The part number is 12A-34

The quantity is 34

The ink color is blue

</PRE>

</BLOCKQUOTE>

<P>

You should be familiar with all the aspects of this script by

now. The line <TT>my($self) = Inventory_item-&gt;new(@_);</TT>

is used to get a refereNCe to an anonymous hash. This hash becomes

the object for the base class.

<P>

To understand that calling the parent constructor creates the

object that becomes the object for the base class, you must remember

that an object <I>is</I> the anonymous hash. Because the parent

constructor creates the anonymous hash, the base class needs a

refereNCe only to that hash in order to add its own properties.

This refereNCe is stored in the <TT>$self</TT>

variable.

<P>

You may also see the variable name <TT>$this</TT>

used to hold the refereNCe in some scripts. Both <TT>$self</TT>

and <TT>$this</TT> are acceptable

in the object-oriented world.<BR>

<p>

<CENTER>

<TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%>

<TR><TD><B>Note</B></TD></TR>

<TR><TD>

<BLOCKQUOTE>

I would actually prefer the variable name <TT>$data</TT> because the hash <TT><I>is</I></TT> the object; therefore, the data <TT><I>is</I></TT> the object. But sometimes, it's good to follow conventional wisdom so that others can more easily understand 
your programs.

</BLOCKQUOTE>



</TD></TR>

</TABLE>

</CENTER>

<P>

<H3><A NAME="ExamplePolymorphism">

Example: Polymorphism</A></H3>

<P>

<I>Polymorphism</I>, although a big word, is a simple coNCept.

It means that methods defined in the base class will override

methods defined in the parent classes. The following small example

clarifies this coNCept:

<BLOCKQUOTE>

<PRE>

package A;

    sub foo {

        print(&quot;Inside A::foo\n&quot;);

    }



package B;

    @ISA = (A);



    sub foo {

        print(&quot;Inside B::foo\n&quot;);

    }



package main;

    B-&gt;foo();

</PRE>

</BLOCKQUOTE>

<P>

This program displays

<BLOCKQUOTE>

<PRE>

Inside B::foo

</PRE>

</BLOCKQUOTE>

<P>

The <TT>foo()</TT> defined in class

<TT>B</TT> overrides the definition

that was inherited from class <TT>A</TT>.

<P>

Polymorphism is mainly used to add or extend the fuNCtionality

of an existing class without reprogramming the whole class. Listing

14.4 uses polymorphism to override the <TT>qtyChange()</TT>

fuNCtion inherited from <TT>Inventory_item</TT>.

In addition, it shows how to call a method in a parent class when

the specific parent class name (also known as the <TT><I>SUPER</I></TT>

class) is unknown.

<P>

<IMG SRC="pseudo.gif" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/pseudo.gif" BORDER=1 ALIGN=RIGHT><p>

<BLOCKQUOTE>

<I>Start a definition of the </I><TT><I>Inventory_item</I></TT><I>

class.<BR>

Define the constructor for the class.<BR>

Get the name of the class from the parameter array.<BR>

Assign the rest of the parameters to the </I><TT><I>%params</I></TT><I>

hash.<BR>

Bless the anonymous hash with the class name.<BR>

Use </I><TT><I>%params</I></TT><I>

to initialize the class properties.<BR>

Define the </I><TT><I>qtyChange()</I></TT><I>

method.<BR>

Get the object refereNCe from the parameter array.<BR>

Get the quantity to change from the parameter array. If there

are no more elements in the </I><TT><I>@_</I></TT><I>,

default to using the quantity 1.<BR>

Use derefereNCing to change the </I><TT><I>QTY_ON_HAND</I></TT><I>

property.<BR>

Start a definition of the </I><TT><I>Pen</I></TT><I>

class.<BR>

Initialize the </I><TT><I>@ISA</I></TT><I>

array to define the parent classes.<BR>

Initialize the </I><TT><I>@PARENT::ISA</I></TT><I>

array to let Perl search the </I><TT><I>@ISA</I></TT><I>

to look for method refereNCes.<BR>

Define the constructor for the class.<BR>

Get the name of the class from the parameter array.<BR>

Assign the rest of the parameters to the </I><TT><I>%params</I></TT><I>

hash.<BR>

Call the constructor for the parent class using the </I><TT><I>PARENT::</I></TT><I>

notation. This searches the classes listed in the </I><TT><I>@ISA</I></TT><I>

array looking for the </I><TT><I>new()</I></TT><I>

fuNCtion  and assigns the resulting object refereNCe to </I><TT><I>$self</I></TT><I>.

<BR>

Create an entry in the anonymous hash for the </I><TT><I>INK_COLOR</I></TT><I>

key.<BR>

Return a refereNCe to the anonymous hash.<BR>

Define the </I><TT><I>qtyChange()</I></TT><I>

method.<BR>

Get the object refereNCe from the parameter array.<BR>

Get the quantity to change from the parameter array. If there

are no more elements in the </I><TT><I>@_</I></TT><I>,

default to using the quantity 100.<BR>

Use derefereNCing to change the </I><TT><I>QTY_ON_HAND</I></TT><I>

property.<BR>

Start the </I><TT><I>main</I></TT><I>

namespace.<BR>

Call the constructor for the </I><TT><I>Pen</I></TT><I>

class. Assign the object refereNCe to </I><TT><I>$item</I></TT><I>.

<BR>

Print the data type of </I><TT><I>$item</I></TT><I>

to show that it is now Pen.<BR>

Print the three property values to verify that the property initialization

 worked.<BR>

Change the quantity by the default amount.<BR>

Print a newline to separate the previous values from the new value.

<BR>

Print the quantity property value to verify that the change method

worked.</I>

</BLOCKQUOTE>

<HR>

<BLOCKQUOTE>

<B>Listing 14.4&nbsp;&nbsp;14LST04.PL-Accessing Methods in Parent

Classes<BR>

</B>

</BLOCKQUOTE>

<BLOCKQUOTE>

<PRE>

package Inventory_item;

    sub new {

        my($class)  = shift;

        my(%params) = @_;

        bless {

            &quot;PART_NUM&quot;    =&gt; $params{&quot;PART_NUM&quot;},

            &quot;QTY_ON_HAND&quot; =&gt; $params{&quot;QTY_ON_HAND&quot;}

        }, $class;

    }





    sub qtyChange {

        my($self)  = shift;

        my($delta)  = $_[0] ? $_[0] : 1;



        $self-&gt;{&quot;QTY_ON_HAND&quot;} += $delta;

    }



package Pen;

    @ISA = (&quot;Inventory_item&quot;);

    @PARENT::ISA = @ISA;



    sub new {

        my($class) = shift;

        my(%params) = @_;

        my($self) = $class-&gt;PARENT::new(@_);



        $self-&gt;{&quot;INK_COLOR&quot;} = $params{&quot;INK_COLOR&quot;};



        return($self);

    }



    sub qtyChange {

        my($self)  = shift;

        my($delta)  = $_[0] ? $_[0] : 100;



        $self-&gt;PARENT::qtyChange($delta);

    }

    



package main;



    $pen = Pen-&gt;new(

        &quot;PART_NUM&quot;=&gt;&quot;12A-34&quot;,

        &quot;QTY_ON_HAND&quot;=&gt;340,

        &quot;INK_COLOR&quot; =&gt; &quot;blue&quot;);



    print(&quot;The data type is &quot;   . ref($pen)                . &quot;\n&quot;);

    print(&quot;The part number is &quot; . %{$pen}-&gt;{'PART_NUM'}    . &quot;\n&quot;);

    print(&quot;The quantity is &quot;    . %{$pen}-&gt;{'QTY_ON_HAND'} . &quot;\n&quot;);

    print(&quot;The ink color is &quot;   . %{$pen}-&gt;{'INK_COLOR'}   . &quot;\n&quot;);



    $pen-&gt;qtyChange();

    print(&quot;\n&quot;);

    print(&quot;The quantity is &quot;    . %{$pen}-&gt;{'QTY_ON_HAND'} . &quot;\n&quot;);

</PRE>

</BLOCKQUOTE>

<HR>

<P>

This program displays

<BLOCKQUOTE>

<PRE>

The data type is Pen

The part number is 12A-34

The quantity is 340

The ink color is blue



The quantity is 440

</PRE>

</BLOCKQUOTE>

<P>

The first interesting line in the preceding example is <TT>my($delta)

 = $_[0] ? $_[0] : 1;</TT>. This line checks to see if

a parameter was passed to <TT>Inventory_item::qtychange()</TT>

and if not, assigns a value of 1 to <TT>$delta</TT>.

This line of code uses the <TT>ternary</TT>

operator to determine if <TT>$_[0]</TT>

has a value or not. A zero is used as the subscript because the

class refereNCe was shifted out of the parameter array and into

<TT>$self</TT>.

<P>

The next interesting line is <TT>@PARENT::ISA

= @ISA;</TT>. This assignment lets you refer to a method

defined in the parent class. Perl searches the parent hierarchy

(the <TT>@ISA</TT> array) until a

definition is found for the requested fuNCtion.

<P>

The <TT>Pen::new()</TT> fuNCtion uses

the <TT>@PARENT::ISA</TT> to find

the parent constructor using this line: <TT>my($self)

= $class-&gt;PARENT::new(@_);</TT>. I don't really recommend

calling parent constructors in this manner because the constructor

that gets called will depend on the order of classes in the <TT>@ISA</TT>

array. Having code that is dependent on an array keeping a specific

order is a recipe for disaster; you might forget about the dependeNCy

and spend hours trying to find the problem. However, I thought

you should see how it works. Because the <TT>$class</TT>

variable (which is equal to <TT>Pen</TT>)

is used to locate the parent constructor, the hash will be blessed

with the name of the base <TT>Pen</TT>

class-one small advantage of this technique. This is shown by

⌨️ 快捷键说明

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