ch13_15.htm

来自「By Tom Christiansen and Nathan Torkingto」· HTM 代码 · 共 793 行 · 第 1/2 页

HTM
793
字号
<HTML><HEAD><TITLE>Recipe 13.14. Overloading Operators (Perl Cookbook)</TITLE><METANAME="DC.title"CONTENT="Perl Cookbook"><METANAME="DC.creator"CONTENT="Tom Christiansen &amp; Nathan Torkington"><METANAME="DC.publisher"CONTENT="O'Reilly &amp; Associates, Inc."><METANAME="DC.date"CONTENT="1999-07-02T01:42:31Z"><METANAME="DC.type"CONTENT="Text.Monograph"><METANAME="DC.format"CONTENT="text/html"SCHEME="MIME"><METANAME="DC.source"CONTENT="1-56592-243-3"SCHEME="ISBN"><METANAME="DC.language"CONTENT="en-US"><METANAME="generator"CONTENT="Jade 1.1/O'Reilly DocBook 3.0 to HTML 4.0"><LINKREV="made"HREF="mailto:online-books@oreilly.com"TITLE="Online Books Comments"><LINKREL="up"HREF="ch13_01.htm"TITLE="13. Classes, Objects, and Ties"><LINKREL="prev"HREF="ch13_14.htm"TITLE="13.13. Coping with Circular Data Structures"><LINKREL="next"HREF="ch13_16.htm"TITLE="13.15. Creating Magic Variables with tie"></HEAD><BODYBGCOLOR="#FFFFFF"><img alt="Book Home" border="0" src="gifs/smbanner.gif" usemap="#banner-map" /><map name="banner-map"><area shape="rect" coords="1,-2,616,66" href="index.htm" alt="Perl Cookbook"><area shape="rect" coords="629,-11,726,25" href="jobjects/fsearch.htm" alt="Search this book" /></map><div class="navbar"><p><TABLEWIDTH="684"BORDER="0"CELLSPACING="0"CELLPADDING="0"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch13_14.htm"TITLE="13.13. Coping with Circular Data Structures"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 13.13. Coping with Circular Data Structures"BORDER="0"></A></TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><B><FONTFACE="ARIEL,HELVETICA,HELV,SANSERIF"SIZE="-1"><ACLASS="chapter"REL="up"HREF="ch13_01.htm"TITLE="13. Classes, Objects, and Ties"></A></FONT></B></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch13_16.htm"TITLE="13.15. Creating Magic Variables with tie"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 13.15. Creating Magic Variables with tie"BORDER="0"></A></TD></TR></TABLE></DIV><DIVCLASS="sect1"><H2CLASS="sect1"><ACLASS="title"NAME="ch13-15937">13.14. Overloading Operators</A></H2><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch13-pgfId-1795">Problem<ACLASS="indexterm"NAME="ch13-idx-1000004655-0"></A><ACLASS="indexterm"NAME="ch13-idx-1000004655-1"></A><ACLASS="indexterm"NAME="ch13-idx-1000004655-2"></A></A></H3><PCLASS="para">You want to use familiar operators like <CODECLASS="literal">==</CODE> or <CODECLASS="literal">+</CODE> on objects from a class you've written, or you want to define the print interpolation value for objects.</P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch13-pgfId-1801">Solution</A></H3><PCLASS="para">Use the <CODECLASS="literal">use</CODE> <CODECLASS="literal">overload</CODE> pragma. Here are two of the most common and useful operators to overload:</P><PRECLASS="programlisting">use overload ('&lt;=&gt;' =&gt; \&amp;threeway_compare);sub threeway_compare {    my ($s1, $s2) = @_;    uc($s1-&gt;{NAME}) cmp uc($s2-&gt;{NAME});} use overload ( '&quot;&quot;'  =&gt; \&amp;stringify );sub stringify {    my $self = shift;    return sprintf &quot;%s (%05d)&quot;,             ucfirst(lc($self-&gt;{NAME})),            $self-&gt;{IDNUM};}</PRE></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch13-pgfId-1833">Discussion</A></H3><PCLASS="para">When you use built-in types, certain operators apply, like <CODECLASS="literal">+</CODE> for addition or <CODECLASS="literal">.</CODE> for string catenation. With the <CODECLASS="literal">use</CODE> <CODECLASS="literal">overload</CODE> pragma, you can customize these operators so they do something special on your own objects.</P><PCLASS="para">This pragma takes a list of operator/function call pairs, such as:</P><PRECLASS="programlisting">package TimeNumber;use overload '+' =&gt; \&amp;my_plus,             '-' =&gt; \&amp;my_minus,             '*' =&gt; \&amp;my_star,             '/' =&gt; \&amp;my_slash;</PRE><PCLASS="para">Now, those four operators can be used with objects of class TimeNumber, and the listed functions will be called. These functions can do anything you'd like.</P><PCLASS="para">Here's a simple example of an overload of <CODECLASS="literal">+</CODE> for use with an object that holds hours, minutes, and seconds. It assumes that both operands are of a class that has a <CODECLASS="literal">new</CODE> method that can be called as an object method, and that the structure names are as shown:</P><PRECLASS="programlisting">sub my_plus {    my($left, $right) = @_;    my $answer = $left-&gt;<CODECLASS="literal">new();</CODE>    $answer-&gt;{SECONDS} = $left-&gt;{SECONDS} + $right-&gt;{SECONDS};    $answer-&gt;{MINUTES} = $left-&gt;{MINUTES} + $right-&gt;{MINUTES};    $answer-&gt;{HOURS}   = $left-&gt;{HOURS}   + $right-&gt;{HOURS};    if ($answer-&gt;{SECONDS} &gt;= 60) {        $answer-&gt;{SECONDS} %= 60;        $answer-&gt;{MINUTES} ++;    }     if ($answer-&gt;{MINUTES} &gt;= 60) {        $answer-&gt;{MINUTES} %= 60;        $answer-&gt;{HOURS}   ++;    }     return $answer;} </PRE><PCLASS="para">It's a good idea to overload numeric operators only when the objects themselves are mirroring some sort of numeric construct, such as complex or infinite precision numbers, vectors, or matrices. Otherwise the code is too hard to understand, leading users to invalid assumptions. Imagine a class that modelled a country. If you can add one country to another, couldn't you subtract one country from another? As you see, using operator overloading for non-mathematical things rapidly becomes ridiculous.</P><PCLASS="para">You may compare objects (and, in fact, any reference) using either <CODECLASS="literal">==</CODE> or <CODECLASS="literal">eq</CODE>, but this only tells you whether the addresses are the same. (Using == is about ten times faster than <CODECLASS="literal">eq</CODE> though.) Because an object is a higher-level notion that a raw machine address, you often want to define your own notion of what it takes for two of them to be equal to each other.</P><PCLASS="para">Two operators frequently overloaded even for a non-numeric class are the comparison and string interpolation operators. Both the &lt;=&gt; and the <CODECLASS="literal">cmp</CODE> operators can be overloaded, although the former is more prevalent. Once the spaceship operator &lt;=&gt;, is defined for an object, you can also use <CODECLASS="literal">==</CODE>, <CODECLASS="literal">!=</CODE>, &lt;, &lt;=, &gt;, and &gt;= as well. This lets objects be compared. If ordering is not desired, only overload <CODECLASS="literal">==</CODE>. Similarly, an overloaded <CODECLASS="literal">cmp</CODE> is used for <CODECLASS="literal">lt</CODE>, <CODECLASS="literal">gt</CODE>, and other string comparisons if they aren't explicitly overloaded.</P><PCLASS="para">The string interpolation operator goes by the unlikely name of <CODECLASS="literal">&quot;&quot;</CODE>, that is, two double quotes. This operator is triggered whenever a conversion to a string is called for, such as within double or back quotes or when passed to the <CODECLASS="literal">print</CODE> function.</P><PCLASS="para">Read the documentation on the <CODECLASS="literal">overload</CODE> pragma that comes with Perl. Perl's operator overloading has some elaborate features, such as string and numeric conversion methods, autogenerating missing methods, and reversing operands if needed, as in <CODECLASS="literal">5</CODE> <CODECLASS="literal">+</CODE> <CODECLASS="literal">$a</CODE> where <CODECLASS="literal">$a</CODE> is an object.</P></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch13-23490">Example: Overloaded StrNum Class</A></H3><PCLASS="para">Here's a <ACLASS="indexterm"NAME="ch13-idx-1000005059-0"></A><ACLASS="indexterm"NAME="ch13-idx-1000005059-1"></A>StrNum class that lets you use strings with numeric operators. Yes, we're about to do something we advised against &nbsp;-  that is, use numeric operators on non-numeric entities &nbsp;-  but programmers from other backgrounds are always expecting <CODECLASS="literal">+</CODE> and <CODECLASS="literal">==</CODE> to work on strings. This is a simple way to demonstrate operator overloading. We almost certainly wouldn't use this in a time-critical production program due to performance concerns. It's also an interesting illustration of using a constructor of the same name as the class, something that C++ and Python programmers may take comfort in.</P><PRECLASS="programlisting">#!/usr/bin/perl# show_strnum - demo operator overloadinguse StrNum;               $x = StrNum(&quot;Red&quot;); $y = StrNum(&quot;Black&quot;);$z = $x + $y; $r = $z * 3;print &quot;values are $x, $y, $z, and $r\n&quot;;print &quot;$x is &quot;, $x &lt; $y ? &quot;LT&quot; : &quot;GE&quot;, &quot; $y\n&quot;;<BCLASS="emphasis.bold">values are Red, Black, RedBlack, and 0</B><BCLASS="emphasis.bold">Red is GE Black</B></PRE><PCLASS="para">The class is shown in <ACLASS="xref"HREF="ch13_15.htm#ch13-32753"TITLE="StrNum">Example 13.1</A>.</P><DIVCLASS="example"><H4CLASS="example"><ACLASS="title"NAME="ch13-32753">Example 13.1: StrNum</A></H4><PRECLASS="programlisting">package StrNum;use Exporter ();@ISA = 'Exporter';@EXPORT = qw(StrNum);  # unusualuse overload        (        '&lt;=&gt;'   =&gt; \&amp;spaceship,        'cmp'   =&gt; \&amp;spaceship,        '&quot;&quot;'    =&gt; \&amp;stringify,        'bool'  =&gt; \&amp;boolify,        '0+'    =&gt; \&amp;numify,        '+'     =&gt; \&amp;concat,        '*'     =&gt; \&amp;repeat,);# constructorsub StrNum {     my ($value) = @_;     return bless \$value; } sub stringify { ${ $_[0] } } sub numify    { ${ $_[0] } } sub boolify   { ${ $_[0] } } # providing &lt;=&gt; gives us &lt;, ==, etc. for free.sub spaceship {     my ($s1, $s2, $inverted) = @_;    return $inverted ? $$s2 cmp $$s1 : $$s1 cmp $$s2;

⌨️ 快捷键说明

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