📄 ch12_05.htm
字号:
<html><head><title>Class Inheritance (Programming Perl)</title><!-- STYLESHEET --><link rel="stylesheet" type="text/css" href="../style/style1.css"><!-- METADATA --><!--Dublin Core Metadata--><meta name="DC.Creator" content=""><meta name="DC.Date" content=""><meta name="DC.Format" content="text/xml" scheme="MIME"><meta name="DC.Generator" content="XSLT stylesheet, xt by James Clark"><meta name="DC.Identifier" content=""><meta name="DC.Language" content="en-US"><meta name="DC.Publisher" content="O'Reilly & Associates, Inc."><meta name="DC.Source" content="" scheme="ISBN"><meta name="DC.Subject.Keyword" content=""><meta name="DC.Title" content="Class Inheritance"><meta name="DC.Type" content="Text.Monograph"></head><body><!-- START OF BODY --><!-- TOP BANNER --><img src="gifs/smbanner.gif" usemap="#banner-map" border="0" alt="Book Home"><map name="banner-map"><AREA SHAPE="RECT" COORDS="0,0,466,71" HREF="index.htm" ALT="Programming Perl"><AREA SHAPE="RECT" COORDS="467,0,514,18" HREF="jobjects/fsearch.htm" ALT="Search this book"></map><!-- TOP NAV BAR --><div class="navbar"><table width="515" border="0"><tr><td align="left" valign="top" width="172"><a href="ch12_04.htm"><img src="../gifs/txtpreva.gif" alt="Previous" border="0"></a></td><td align="center" valign="top" width="171"><a href="ch12_01.htm">Chapter 12: Objects</a></td><td align="right" valign="top" width="172"><a href="ch12_06.htm"><img src="../gifs/txtnexta.gif" alt="Next" border="0"></a></td></tr></table></div><hr width="515" align="left"><!-- SECTION BODY --><h2 class="sect1">12.5. Class Inheritance</h2><a name="INDEX-2435"></a><a name="INDEX-2436"></a><a name="INDEX-2437"></a><p><a name="INDEX-2438"></a>As with the rest of Perl's object system, inheritance of one class byanother requires no special syntax to be added to the language. When youinvoke a method for which Perl finds no subroutine in the invocant'spackage, that package's <tt class="literal">@ISA</tt> array<a href="#FOOTNOTE-5">[5]</a> is examined. This is how Perlimplements inheritance: each element of a given package's <tt class="literal">@ISA</tt> arrayholds the name of another package, which is searched when methods are missing. For example, the following makes the <tt class="literal">Horse</tt> class asubclass of the <tt class="literal">Critter</tt> class. (We declare <tt class="literal">@ISA</tt> with <tt class="literal">our</tt>because it has to be a package variable, not a lexical declared with<tt class="literal">my</tt>.)<blockquote><pre class="programlisting">package Horse;our @ISA = "Critter";</pre></blockquote><a name="INDEX-2439"></a>You should now be able to use a <tt class="literal">Horse</tt> class or object everywherethat a <tt class="literal">Critter</tt> was previously used. If your new class passesthis <em class="emphasis">empty subclass test</em>, you know that <tt class="literal">Critter</tt> is a properbase class, fit for inheritance.</p><blockquote class="footnote"><a name="FOOTNOTE-5"></a><p>[5] Pronounced "is a", asin "A horse is a critter."</p></blockquote><p>Suppose you have a <tt class="literal">Horse</tt> object in <tt class="literal">$steed</tt> and invoke a <tt class="literal">move</tt>method on it:<blockquote><pre class="programlisting">$steed->move(10);</pre></blockquote>Because <tt class="literal">$steed</tt> is a <tt class="literal">Horse</tt>,Perl's first choice for that method is the<tt class="literal">Horse::move</tt> subroutine. If there isn't one,instead of raising a run-time exception, Perl consults the firstelement of <tt class="literal">@Horse::ISA</tt>, which directs it to look inthe <tt class="literal">Critter</tt> package for<tt class="literal">Critter::move</tt>. If this subroutine isn't foundeither, and <tt class="literal">Critter</tt> has <em class="emphasis">its</em>own <tt class="literal">@Critter::ISA</tt> array, then that too will beconsulted for the name of an ancestral package that might supply a<tt class="literal">move</tt> method, and so on back up the inheritancehierarchy until we come to a package without an<tt class="literal">@ISA</tt>.</p><p><a name="INDEX-2440"></a><a name="INDEX-2441"></a><a name="INDEX-2442"></a>The situation we just described is <em class="emphasis">single inheritance</em>, where eachclass has only one parent. Such inheritance is like a linked list ofrelated packages. Perl also supports <em class="emphasis">multiple inheritance</em>; justadd more packages to the class's <tt class="literal">@ISA</tt>. This kind of inheritanceworks more like a tree data structure, because every package can havemore than one immediate parent. Some people find this to be sexier.</p><p><a name="INDEX-2443"></a><a name="INDEX-2444"></a>When you invoke a method <em class="replaceable">methname</em> on an invocant of type<em class="replaceable">classname</em>, Perl tries six different ways to find a subroutine to use:</p><ol><li><p>First, Perl looks in the invocant's own package for a subroutine named<em class="replaceable">classname</em><tt class="literal">::</tt><em class="replaceable">methname</em>. If that fails, inheritance kicks in, andwe go to step 2.</p></li><li><p>Next, Perl checks for methods inheritedfrom base classes by looking in all <em class="replaceable">parent</em> packages listed in<tt class="literal">@</tt><em class="replaceable">classname</em><tt class="literal">::ISA</tt> for a <em class="replaceable">parent</em><tt class="literal">::</tt><em class="replaceable">methname</em> subroutine. The search is left-to-right, recursive, and depth-first. Therecursion assures that grandparent classes, great-grandparentclasses, great-great-grandparent classes, and so on, are all searched.</p></li><li><p>If that fails, Perl looks for a subroutine named<tt class="literal">UNIVERSAL::</tt><em class="replaceable">methname</em>.</p></li><li><p>At this point, Perl gives up on <em class="replaceable">methname</em> and starts looking for an<tt class="literal">AUTOLOAD</tt>. First, it looks for a subroutine named <em class="replaceable">classname</em><tt class="literal">::AUTOLOAD</tt>.</p></li><li><p>Failing that, Perl searches all <em class="replaceable">parent</em> packages listed in<tt class="literal">@</tt><em class="replaceable">classname</em><tt class="literal">::ISA</tt>, for any <em class="replaceable">parent</em><tt class="literal">::AUTOLOAD</tt> subroutine. The search is again left-to-right, recursive, and depth-first.</p></li><li><p>Finally, Perl looks for a subroutine named <tt class="literal">UNIVERSAL::AUTOLOAD</tt>.</p></li></ol><p>Perl stops after the first successful attempt and invokes thatsubroutine. If no subroutine is found, an exception is raised, onethat you'll see frequently:<blockquote><pre class="programlisting">Can't locate object method "<em class="replaceable">methname</em>" via package "<em class="replaceable">classname</em>"</pre></blockquote><a name="INDEX-2445"></a>If you've built a debugging version of Perl using the<span class="option">-DDEBUGGING</span> option to your C compiler, by usingPerl's <span class="option">-Do</span> switch, you can watch it gothrough each of these steps when it resolves method invocation.</p><p>We will discuss the inheritance mechanism in more detail as we go along.</p><h3 class="sect2">12.5.1. Inheritance Through @ISA</h3><p><a name="INDEX-2446"></a><a name="INDEX-2447"></a><a name="INDEX-2448"></a><a name="INDEX-2449"></a><a name="INDEX-2450"></a>If <tt class="literal">@ISA</tt> contains more than one package name, the packages are all searchedin left-to-right order. The search is depth-first, so if you have a<tt class="literal">Mule</tt> class set up for inheritance this way:<blockquote><pre class="programlisting">package Mule;our @ISA = ("Horse", "Donkey");</pre></blockquote>Perl looks for any methods missing from <tt class="literal">Mule</tt> first in <tt class="literal">Horse</tt> (andany of its ancestors, like <tt class="literal">Critter</tt>) before going on to searchthrough <tt class="literal">Donkey</tt> and its ancestors.</p><p>If a missing method is found in a base class, Perl internally cachesthat location in the current class for efficiency, so the next timeit has to find the method, it doesn't have to look as far. Changing <tt class="literal">@ISA</tt> or defining new methods invalidates thecache and causes Perl to perform the lookup again.</p><p>When Perl searches for a method, it makes sure that you haven'tcreated a circular inheritance hierarchy. This could happen iftwo classes inherit from one another, even indirectly throughother classes. Trying to be your own great-grandfather is tooparadoxical even for Perl, so the attempt raises an exception.However, Perl does not consider it an error to inherit from morethan one class sharing a common ancestry, which is rather like cousinsmarrying. Your inheritance hierarchy just stops looking like atree and starts to look like a directed acyclic graph. This doesn'tbother Perl--so long as the graph really is acyclic.</p><p><a name="INDEX-2451"></a><a name="INDEX-2452"></a>When you set <tt class="literal">@ISA</tt>, the assignment normally happens at run time,so unless you take precautions, code in <tt class="literal">BEGIN</tt>, <tt class="literal">CHECK</tt>, or<tt class="literal">INIT</tt> blocks won't be able to use the inheritance hierarchy. Oneprecaution (or convenience) is the <tt class="literal">use base</tt> pragma, which letsyou <tt class="literal">require</tt> classes and add them to <tt class="literal">@ISA</tt> at compile time.Here's how you might use it:<blockquote><pre class="programlisting">package Mule;use base ("Horse", "Donkey"); # declare superclasses</pre></blockquote>This is a shorthand for:<blockquote><pre class="programlisting">package Mule;BEGIN { our @ISA = ("Horse", "Donkey"); require Horse; require Donkey;}</pre></blockquote>except that <tt class="literal">use base</tt> also takes into account any <tt class="literal">use fields</tt>declarations.<a name="INDEX-2453"></a></p><p><a name="INDEX-2454"></a>Sometimes folks are surprised that including a class in <tt class="literal">@ISA</tt>doesn't <tt class="literal">require</tt> the appropriate module for you. That's becausePerl's class system is largely orthogonal to its module system. Onefile can hold many classes (since they're just packages), and onepackage may be mentioned in many files. But in the most commonsituation, where one package and one class and one module and one fileall end up being pretty interchangeable if you squint enough, the<tt class="literal">use base</tt> pragma offers a declarative syntax that establishesinheritance, loads in module files, and accommodates any declaredbase class fields. It's one of those convenient diagonals we keep mentioning.</p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -