📄 ei18.htm
字号:
// <A HREF="./EI49_FR.HTM#8392" TARGET="_top">Item 49</A> for vector info
</PRE>
</UL><A NAME="5831"></A>
<UL><PRE> BoundsCheckingStatus checkingBounds;
};
</PRE>
</UL><A NAME="5837"></A>
<P><A NAME="dingp14"></A>
The member functions declared so far are the ones that require basically no thinking (or pondering or ruminating). You have a constructor to allow clients to specify each array's bounds, a copy constructor, an assignment operator, and a destructor. In this case, you've declared the destructor nonvirtual, which implies that this class is not to be used as a base class (see <A HREF="./EI14_FR.HTM#223029" TARGET="_top">Item 14</A>).<SCRIPT>create_link(14);</SCRIPT>
</P>
<A NAME="5847"></A>
<P><A NAME="dingp15"></A>
The declaration of the assignment operator is actually less clear-cut than it might at first appear. After all, built-in arrays in C++ don't allow assignment, so you might want to disallow it for your <CODE>Array</CODE> objects, too (see <A HREF="./EI27_FR.HTM#6406" TARGET="_top">Item 27</A>). On the other hand, the array-like <CODE>vector</CODE> template (in the standard library — see <A HREF="./EI49_FR.HTM#8392" TARGET="_top">Item 49</A>) permits assignments between <CODE>vector</CODE> objects. In this example, you'll follow <CODE>vector</CODE>'s lead, and that decision, as you'll see below, will affect other portions of the classes's <NOBR>interface.<SCRIPT>create_link(15);</SCRIPT>
</NOBR></P>
<A NAME="5851"></A>
<P><A NAME="dingp16"></A>
<A NAME="p82"></A>Old-time C hacks would cringe to see this interface. Where is the support for declaring an array of a particular size? It would be easy enough to add another <NOBR>constructor,<SCRIPT>create_link(16);</SCRIPT>
</NOBR></P>
<A NAME="5852"></A>
<UL><PRE>Array(int size,
BoundsCheckingStatus check = NO_CHECK_BOUNDS);
</PRE>
</UL><A NAME="5853"></A>
<P><A NAME="dingp17"></A>
but this is not part of a minimal interface, because the constructor taking an upper and lower bound can be used to accomplish the same thing. Nonetheless, it might be a wise political move to humor the old geezers, possibly under the rubric of consistency with the base <NOBR>language.<SCRIPT>create_link(17);</SCRIPT>
</NOBR></P>
<A NAME="5854"></A>
<P><A NAME="dingp18"></A>
What other functions do you need? Certainly it is part of a complete interface to index into an <NOBR>array:<SCRIPT>create_link(18);</SCRIPT>
</NOBR></P>
<A NAME="5855"></A>
<UL><PRE>// return element for read/write
T& operator[](int index);
</PRE>
</UL><A NAME="5857"></A>
<UL><PRE>// return element for read-only
const T& operator[](int index) const;
</PRE>
</UL><A NAME="5858"></A>
<P><A NAME="dingp19"></A>
By declaring the same function twice, once <CODE>const</CODE> and once non-<CODE>const</CODE>, you provide support for both <CODE>const</CODE> and non-<CODE>const</CODE> <CODE>Array</CODE> objects. The difference in return types is significant, as is explained in <A HREF="./EI21_FR.HTM#6003" TARGET="_top">Item 21</A>.<SCRIPT>create_link(19);</SCRIPT>
</P>
<A NAME="5862"></A>
<P><A NAME="dingp20"></A>
As it now stands, the <CODE>Array</CODE> template supports construction, destruction, pass-by-value, assignment, and indexing, which may strike you as a complete interface. But look closer. Suppose a client wants to loop through an array of integers, printing out each of its elements, like <NOBR>so:<SCRIPT>create_link(20);</SCRIPT>
</NOBR></P>
<A NAME="5863"></A>
<UL><PRE>Array<int> a(10, 20); // bounds on a are 10 to 20
</PRE>
</UL><A NAME="5864"></A>
<UL><PRE>...
</PRE>
</UL><A NAME="5865"></A>
<UL><PRE>for (int i = <I>lower bound of a</I>; i <= <I>upper bound of a</I>; ++i)
cout << "a[" << i << "] = " << a[i] << '\n';
</PRE>
</UL><A NAME="5866"></A>
<P><A NAME="dingp21"></A>
How is the client to get the bounds of <CODE>a</CODE>? The answer depends on what happens during assignment of <CODE>Array</CODE> objects, i.e., on what happens inside <CODE>Array::operator=</CODE>. In particular, if assignment can change the bounds of an <CODE>Array</CODE> object, you must provide member functions to return the current bounds, because the client has no way of knowing <I>a priori</I> what the bounds are at any given point in the program. In the example above, if <CODE>a</CODE> was the target of an assignment between the time it was defined and the time it was used in the loop, the client would have no way to determine the current bounds of <CODE>a</CODE>.<SCRIPT>create_link(21);</SCRIPT>
</P>
<A NAME="5868"></A>
<P><A NAME="dingp22"></A>
On the other hand, if the bounds of an <CODE>Array</CODE> object cannot be changed during assignment, then the bounds are fixed at the point of <A NAME="p83"></A>definition, and it would be possible (though cumbersome) for a client to keep track of these bounds. In that case, though it would be convenient to offer functions to return the current bounds, such functions would not be part of a truly minimal <NOBR>interface.<SCRIPT>create_link(22);</SCRIPT>
</NOBR></P>
<A NAME="5869"></A>
<P><A NAME="dingp23"></A>
Proceeding on the assumption that assignment can modify the bounds of an object, the bounds functions could be declared <NOBR>thus:<SCRIPT>create_link(23);</SCRIPT>
</NOBR></P>
<A NAME="5870"></A>
<UL><PRE>int lowBound() const;
int highBound() const;
</PRE>
</UL><A NAME="5871"></A>
<P><A NAME="dingp24"></A>
Because these functions don't modify the object on which they are invoked, and because you prefer to use <CODE>const</CODE> whenever you can (see <A HREF="./EI21_FR.HTM#6003" TARGET="_top">Item 21</A>), these are both declared <CODE>const</CODE> member functions. Given these functions, the loop above would be written as <NOBR>follows:<SCRIPT>create_link(24);</SCRIPT>
</NOBR></P>
<A NAME="5875"></A>
<UL><PRE>for (int i = a.lowBound(); i <= a.highBound(); ++i)
cout << "a[" << i << "] = " << a[i] << '\n';
</PRE>
</UL><A NAME="5876"></A>
<P><A NAME="dingp25"></A>Needless to say, for such a loop to work for an array of objects of type <CODE>T</CODE>, an <CODE>operator<<</CODE> function must be defined for objects of type <CODE>T</CODE>. (That's not quite true. What must exist is an <CODE>operator<<</CODE> for <CODE>T</CODE> or for some other type to which <CODE>T</CODE> may be implicitly converted (see <A HREF="../MEC/MI5_FR.HTM#5970" TARGET="_top">Item M5</A>). But you get the <NOBR>idea.)<SCRIPT>create_link(25);</SCRIPT>
</NOBR></P>
<A NAME="5877"></A>
<P><A NAME="dingp26"></A>
Some designers would argue that the <CODE>Array</CODE> class should also offer a function to return the number of elements in an <CODE>Array</CODE> object. The number of elements is simply <CODE>highBound()-lowBound()+1</CODE>, so such a function is not really necessary, but in view of the frequency of off-by-one errors, it might not be a bad idea to add such a <NOBR>function.<SCRIPT>create_link(26);</SCRIPT>
</NOBR></P>
<A NAME="5879"></A>
<P><A NAME="dingp27"></A>
Other functions that might prove worthwhile for this class include those for input and output, as well as the various relational operators (e.g., <CODE><</CODE>, <CODE>></CODE>, <CODE>==</CODE>, etc.). None of those functions is part of a minimal interface, however, because they can all be implemented in terms of loops containing calls to <CODE>operator[]</CODE>.<SCRIPT>create_link(27);</SCRIPT>
</P>
<A NAME="5881"></A>
<P><A NAME="dingp28"></A>
Speaking of functions like <CODE>operator<<</CODE>, <CODE>operator>></CODE>, and the relational operators, <A HREF="./EI19_FR.HTM#5887" TARGET="_top">Item 19</A> discusses why they are frequently implemented as non-member friend functions instead of as member functions. That being the case, don't forget that friend functions are, for all practical purposes, part of a class's interface. That means that friend functions count toward a class interface's completeness and <NOBR>minimalness.<SCRIPT>create_link(28);</SCRIPT>
</NOBR></P>
<DIV ALIGN="CENTER"><FONT SIZE="-1">Back to <A HREF="./EDESGNFR.HTM" TARGET="_top">Design and Declaration</A> <BR> Continue to <A HREF="./EI19_FR.HTM" TARGET="_top">Item 19: Differentiate among member functions, non-member functions, and friend functions.</A></FONT></DIV>
</BODY>
</HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -