📄 ch19.htm
字号:
107: cout << "theZoo[" << j << "]:\t";108: theZoo[j].Display();109: cout << endl;110: }111:112: for (int k = 0; k < theArray.GetSize(); k++)113: delete &theZoo[j];114: return 0;<TT>115: }</TT>Output: theArray[0]: 0 theZoo[0]: 0theArray[1]: 2 theZoo[1]: 3theArray[2]: 4 theZoo[2]: 6theArray[3]: 6 theZoo[3]: 9theArray[4]: 8 theZoo[4]: 12theArray[5]: 10 theZoo[5]: 15theArray[6]: 12 theZoo[6]: 18theArray[7]: 14 theZoo[7]: 21theArray[8]: 16 theZoo[8]: 24theArray[9]: 18 theZoo[9]: 27</FONT></PRE><P><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B>Lines 8 to 26 provide a stripped-down<TT>Animal</TT> class, created here so that there are objects of a user-defined typeto add to the array.<BR><BR>Line 29 declares that what follows is a template, and that the parameter to the templateis a type, designated as <TT>T</TT>. The <TT>Array</TT> class has two constructorsas shown, the first of which takes a size and defaults to the constant integer <TT>DefaultSize</TT>.</P><P>The assignment and offset operators are declared, with the latter declaring botha <TT>const</TT> and a non-<TT>const</TT> variant. The only accessor provided is<TT>GetSize()</TT>, which returns the size of the array.</P><P>One can certainly imagine a fuller interface, and, for any serious <TT>Array</TT>program, what has been supplied here would be inadequate. At a minimum, operatorsto remove elements, to expand the array, to pack the array, and so forth would berequired.</P><P>The private data consists of the size of the array and a pointer to the actualin-memory array of objects.<H3 ALIGN="CENTER"><A NAME="Heading12"></A><FONT COLOR="#000077">Template Functions</FONT></H3><P>If you want to pass an array object to a function, you must pass a particularinstance of the array, not a template. Therefore, if <TT>SomeFunction()</TT> takesan integer array as a parameter, you may write</P><PRE><FONT COLOR="#0066FF">void SomeFunction(Array<int>&); // ok</FONT></PRE><P>but you may not write</P><PRE><FONT COLOR="#0066FF">void SomeFunction(Array<T>&); // error!</FONT></PRE><P>because there is no way to know what a <TT>T&</TT> is. You also may not write</P><PRE><FONT COLOR="#0066FF">void SomeFunction(Array &); // error!</FONT></PRE><P>because there is no class <TT>Array</TT>--only the template and the instances.</P><P>To accomplish the more general approach, you must declare a template function.</P><PRE><FONT COLOR="#0066FF">template <class T>void MyTemplateFunction(Array<T>&); // ok</FONT></PRE><P>Here the function <TT>MyTemplateFunction()</TT> is declared to be a template functionby the declaration on the top line. Note that template functions can have any name,just as other functions can.</P><P>Template functions can also take instances of the template, in addition to theparameterized form. The following is an example:</P><PRE><FONT COLOR="#0066FF">template <class T>void MyOtherFunction(Array<T>&, Array<int>&); // ok</FONT></PRE><P>Note that this function takes two arrays: a parameterized array and an array ofintegers. The former can be an array of any object, but the latter is always an arrayof integers.<H3 ALIGN="CENTER"><A NAME="Heading13"></A><FONT COLOR="#000077">Templates and Friends</FONT></H3><P>Template classes can declare three types of friends:<UL> <LI>A non-template friend class or function. <P> <LI>A general template friend class or function. <P> <LI>A type-specific template friend class or function.</UL><H4 ALIGN="CENTER"><A NAME="Heading14"></A><FONT COLOR="#000077">Non-Template FriendClasses and Functions</FONT></H4><P>It is possible to declare any class or function to be a friend to your templateclass. Each instance of the class will treat the friend properly, as if the declarationof friendship had been made in that particular instance. Listing 19.3 adds a trivialfriend function, <TT>Intrude()</TT>, to the template definition of the <TT>Array</TT>class, and the driver program invokes <TT>Intrude()</TT>. Because it is a friend,<TT>Intrude()</TT> can then access the private data of the <TT>Array</TT>. Becausethis is not a template function, it can only be called on <TT>Array</TT>s of <TT>int</TT>.<BLOCKQUOTE> <P><HR><FONT COLOR="#000077"><B>NOTE:</B></FONT><B> </B>To use Listing 19.3, copy lines 1-26 of Listing 19.2 after line 1 of this listing, and then copy lines 51-86 of Listing 19.2 after line 37 of this listing. <HR></BLOCKQUOTE><P><A NAME="Heading15"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 19.3. Non-templatefriend function.</B></FONT><PRE><FONT COLOR="#0066FF">1: // Listing 19.3 - Type specific friend functions in templates2:3: template <class T> // declare the template and the parameter4: class Array // the class being parameterized5: {6: public:7: // constructors8: Array(int itsSize = DefaultSize);9: Array(const Array &rhs);10: ~Array() { delete [] pType; }11:12: // operators13: Array& operator=(const Array&);14: T& operator[](int offSet) { return pType[offSet]; }15: const T& operator[](int offSet) const 16: { return pType[offSet]; }17: // accessors18: int GetSize() const { return itsSize; }19:20: // friend function21: friend void Intrude(Array<int>);22:23: private:24: T *pType;25: int itsSize;26: };27:28: // friend function. Not a template, can only be used29: // with int arrays! Intrudes into private data.30: void Intrude(Array<int> theArray)31: {32: cout << "\n*** Intrude ***\n";33: for (int i = 0; i < theArray.itsSize; i++)34: cout << "i: " << theArray.pType[i] << endl;35: cout << "\n";36: }37:38: // driver program39: int main()40: {41: Array<int> theArray; // an array of integers42: Array<Animal> theZoo; // an array of Animals43: Animal *pAnimal;44:45: // fill the arrays46: for (int i = 0; i < theArray.GetSize(); i++)47: {48: theArray[i] = i*2;49: pAnimal = new Animal(i*3);50: theZoo[i] = *pAnimal;51: }52:53: int j, k;54: for (j = 0; j < theArray.GetSize(); j++)55: {56: cout << "theZoo[" << j << "]:\t";57: theZoo[j].Display();58: cout << endl;59: }60: cout << "Now use the friend function to ";61: cout << "find the members of Array<int>";62: Intrude(theArray);63:63: // return the allocated memory before the arrays are destroyed.64: for (k = 0; k < theArray.GetSize(); k++)65: delete &theZoo[j];66:67: cout << "\n\nDone.\n";68: return 0;<TT>69: }</TT></FONT><FONT COLOR="#0066FF">Output: theZoo[0]: 0theZoo[1]: 3theZoo[2]: 6theZoo[3]: 9theZoo[4]: 12theZoo[5]: 15theZoo[6]: 18theZoo[7]: 21theZoo[8]: 24theZoo[9]: 27Now use the friend function to find the members of Array<int>*** Intrude ***i: 0i: 2i: 4i: 6i: 8i: 10i: 12i: 14i: 16i: 18Done.</FONT></PRE><P><FONT COLOR="#000077"><B>Analysis: </B></FONT>The declaration of the <TT>Array</TT>template has been extended to include the friend function <TT>Intrude()</TT>. Thisdeclares that every instance of an array will consider <TT>Intrude()</TT> to be afriend function; thus, <TT>Intrude()</TT> will have access to the private memberdata and functions of the array instance.<BR><BR>On line 33, <TT>Intrude()</TT> accesses <TT>itsSize</TT> directly, and on line 34it accesses <TT>pType</TT> directly. This trivial use of these members was unnecessarybecause the <TT>Array</TT> class provides public accessors for this data, but itserves to demonstrate how friend functions can be declared with templates.<H4 ALIGN="CENTER"><A NAME="Heading17"></A><FONT COLOR="#000077">General TemplateFriend Class or Function</FONT></H4><P>It would be helpful to add a display operator to the <TT>Array</TT> class. Oneapproach would be to declare a display operator for each possible type of <TT>Array</TT>,but this would undermine the whole point of having made <TT>Array</TT> a template.</P><P>What is needed is an insertion operator that works for any possible type of <TT>Array</TT>.</P><PRE><FONT COLOR="#0066FF">ostream& operator<< (ostream& Array<T>&);</FONT></PRE><P>To make this work, we need to declare <TT>operator<<</TT> to be a templatefunction.</P><PRE><FONT COLOR="#0066FF">template <class T> ostream& operator<< (ostream&, Array<T>&)</FONT></PRE><P>Now that <TT>operator<<</TT> is a template function, you need only to providean implementation. Listing 19.4 shows the <TT>Array</TT> template extended to includethis declaration and provides the implementation for the <TT>operator<<</TT>.<BLOCKQUOTE> <P><HR><FONT COLOR="#000077"><B>NOTE: </B></FONT>To compile this listing, copy lines 8-26 of Listing 19.2 and insert them between lines 3 and 4. Also copy lines 51-86 of Listing 19.2 and insert them between lines 37 and 38. <HR></BLOCKQUOTE><P><A NAME="Heading18"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 19.4. Usingoperator ostream.</B></FONT><PRE><FONT COLOR="#0066FF">1: #include <iostream.h>2:3: const int DefaultSize = 10;4:5: template <class T> // declare the template and the parameter6: class Array // the class being parameterized7: {8: public:9: // constructors10: Array(int itsSize = DefaultSize);11: Array(const Array &rhs);12: ~Array() { delete [] pType; }13:14: // operators15: Array& operator=(const Array&);16: T& operator[](int offSet) { return pType[offSet]; }17: const T& operator[](int offSet) const 18: { return pType[offSet]; }19: // accessors20: int GetSize() const { return itsSize; }21:22: friend ostream& operator<< (ostream&, Array<T>&);23:24: private:25: T *pType;26: int itsSize;27: };28:29: template <class T>30: ostream& operator<< (ostream& output, Array<T>& theArray)31: {32: for (int i = 0; i<theArray.GetSize(); i++)33: output << "[" << i << "] " << theArray[i] << endl; return output;34: }35:36: enum BOOL { FALSE, TRUE};37:38: int main()39: {40: BOOL Stop = FALSE; // flag for looping41: int offset, value;42: Array<int> theArray;43:44: while (!Stop)45: {46: cout << "Enter an offset (0-9) ";47: cout << "and a value. (-1 to stop): " ;47: cin >> offset >> value;48:49: if (offset < 0)50: break;51:52: if (offset > 9)53: {54: cout << "***Please use values between 0 and 9.***\n";55: continue;56: }57:58: theArray[offset] = value;59: }60:61: cout << "\nHere's the entire array:\n";62: cout << theArray << endl;63: return 0;<TT>64: }</TT></FONT><FONT COLOR="#0066FF">Output: Enter an offset (0-9) and a value. (-1 to stop): 1 10Enter an offset (0-9) and a value. (-1 to stop): 2 20Enter an offset (0-9) and a value. (-1 to stop): 3 30Enter an offset (0-9) and a value. (-1 to stop): 4 40Enter an offset (0-9) and a value. (-1 to stop): 5 50Enter an offset (0-9) and a value. (-1 to stop): 6 60Enter an offset (0-9) and a value. (-1 to stop): 7 70Enter an offset (0-9) and a value. (-1 to stop): 8 80Enter an offset (0-9) and a value. (-1 to stop): 9 90Enter an offset (0-9) and a value. (-1 to stop): 10 10***Please use values between 0 and 9.***Enter an offset (0-9) and a value. (-1 to stop): -1 -1Here's the entire array:[0] 0[1] 10[2] 20[3] 30[4] 40[5] 50[6] 60[7] 70[8] 80[9] 90</FONT></PRE><P><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B>On line 22, the functiontemplate <TT>operator<<()</TT> is declared to be a friend of the <TT>Array</TT>class template. Because <TT>operator<<()</TT> is implemented as a templatefunction, every instance of this parameterized array type will automatically havean <TT>operator<<()</TT>. The implementation for this operator starts on line29. Every member of an array is called in turn. This only works if there is an <TT>operator<<</TT>defined for every type of object stored in the array.<H4 ALIGN="CENTER"><A NAME="Heading20"></A><FONT COLOR="#000077">A Type-SpecificTemplate Friend Class or Function</FONT></H4><P>Although the insertion operator shown in Listing 19.4 works, it is still not quitewhat is needed. Because the declaration of the friend operator on line 29 declaresa template, it will work for any instance of <TT>Array</TT> and any insertion operatortaking an array of any type.</P><P>The insertion operator template shown in Listing 19.4 makes all instances of theinsertion <TT>operator<<</TT> a friend of any instance of <TT>Array</TT>, whetherthe instance of the insertion operator is an integer, an <TT>Animal</TT>, or a <TT>Car</TT>.It makes no sense, however, for an <TT>Animal</TT> insertion operator to be a friendto the insertion operator for an integer array.</P><P>What is needed is for the insertion operator for an array of <TT>int</TT> to bea friend to the <TT>Array</TT> of <TT>int</TT> class, and for the insertion operatorof an array of <TT>Animals</TT> to be a friend to the <TT>Array</TT> of animals instance.</P><P>To accomplish this, modify the declaration of the insertion operator on line 29of Listing 19.4, and remove the words <TT>template <class T></TT>. That is,change line 30 to read</P><PRE><FONT COLOR="#0066FF">friend ostream& operator<< (ostream&, Array<T>&);</FONT></PRE><P>This will use the type (<TT>T</TT>) declared in the template of <TT>Array</TT>.Thus, the <TT>operator<<</TT> for an integer will only work with an array ofintegers, and so forth.<H3 ALIGN="CENTER"><A NAME="Heading21"></A><FONT COLOR="#000077">Using Template Items</FONT></H3><P>You can treat template items as you would any other type. You can pass them asparameters, either by reference or by value, and you can return them as the returnvalues of functions, also by value or by reference. Listing 19.5 demonstrates howto pass template objects.</P><P><A NAME="Heading22"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 19.5. Passingtemplate objects to and from functions.</B></FONT><PRE><FONT COLOR="#0066FF">1: #include <iostream.h>2:3: const int DefaultSize = 10;4:5: // A trivial class for adding to arrays6: class Animal7: {8: public:9: // constructors10: Animal(int);11: Animal();12: ~Animal();13:14: // accessors15: int GetWeight() const { return itsWeight; }16: void SetWeight(int theWeight) { itsWeight = theWeight; }17:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -