📄 ch10.htm
字号:
46: {47: CAT frisky;48: cout << "frisky's age: " << frisky.GetAge() << endl;49: cout << "Setting frisky to 6...\n";50: frisky.SetAge(6);51: cout << "Creating boots from frisky\n";52: CAT boots(frisky);53: cout << "frisky's age: " << frisky.GetAge() << endl;54: cout << "boots' age: " << boots.GetAge() << endl;55: cout << "setting frisky to 7...\n";56: frisky.SetAge(7);57: cout << "frisky's age: " << frisky.GetAge() << endl;58: cout << "boot's age: " << boots.GetAge() << endl;59: return 0;<TT>60: }</TT></FONT><FONT COLOR="#0066FF">Output: frisky's age: 5Setting frisky to 6...Creating boots from friskyfrisky's age: 6boots' age: 6setting frisky to 7...frisky's age: 7boots' age: 6</FONT></PRE><P><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B>On lines 6-19, the <TT>CAT</TT>class is declared. Note that on line 9 a default constructor is declared, and online 10 a copy constructor is declared.<BR>On lines 17 and 18, two member variables are declared, each as a pointer to an integer.Typically there'd be little reason for a class to store <TT>int</TT> member variablesas pointers, but this was done to illustrate how to manage member variables on thefree store.</P><P>The default constructor, on lines 21-27, allocates room on the free store fortwo <TT>int</TT> variables and then assigns values to them.</P><P>The copy constructor begins on line 29. Note that the parameter is <TT>rhs</TT>.It is common to refer to the parameter to a copy constructor as <TT>rhs</TT>, whichstands for right-hand side. When you look at the assignments in lines 33 and 34,you'll see that the object passed in as a parameter is on the right-hand side ofthe equals sign. Here's how it works.</P><P>On lines 31 and 32, memory is allocated on the free store. Then, on lines 33 and34, the value at the new memory location is assigned the values from the existing<TT>CAT</TT>.</P><P>The parameter <TT>rhs</TT> is a <TT>CAT</TT> that is passed into the copy constructoras a constant reference. The member function <TT>rhs.GetAge()</TT> returns the valuestored in the memory pointed to by <TT>rhs</TT>'s member variable <TT>itsAge</TT>.As a <TT>CAT</TT> object, <TT>rhs</TT> has all the member variables of any other<TT>CAT</TT>.</P><P>When the copy constructor is called to create a new <TT>CAT</TT>, an existing<TT>CAT</TT> is passed in as a parameter. The new <TT>CAT</TT> can refer to its ownmember variables directly; however, it must access <TT>rhs</TT>'s member variablesusing the public accessor methods.</P><P>Figure 10.3 diagrams what is happening here. The values pointed to by the existing<TT>CAT</TT> are copied to the memory allocated for the new <TT>CAT</TT><BR><BR><A NAME="Heading22"></A><A HREF="102cp03.jpg" tppabs="http://www.mcp.com/814147200/0-672/0-672-31070-8/art/ch10/102cp03.jpg"><FONT COLOR="#000077">Figure10.3.</FONT></A><FONT COLOR="#000077"> </FONT><I>Deep copy illustrated.</I><BR><BR>On line 47, a <TT>CAT</TT> called <TT>frisky</TT> is created. <TT>frisky</TT>'s ageis printed, and then his age is set to 6 on line 50. On line 52, a new <TT>CAT</TT><TT>boots</TT> is created, using the copy constructor and passing in <TT>frisky</TT>.Had <TT>frisky</TT> been passed as a parameter to a function, this same call to thecopy constructor would have been made by the compiler.<BR><BR>On lines 53 and 54, the ages of both <TT>CAT</TT>s are printed. Sure enough, <TT>boots</TT>has <TT>frisky</TT>'s age, <TT>6</TT>, not the default age of <TT>5</TT>. On line56, <TT>frisky</TT>'s age is set to <TT>7</TT>, and then the ages are printed again.This time <TT>frisky</TT>'s age is <TT>7</TT>, but <TT>boots</TT>' age is still <TT>6</TT>,demonstrating that they are stored in separate areas of memory.</P><P>When the <TT>CAT</TT>s fall out of scope, their destructors are automaticallyinvoked. The implementation of the <TT>CAT</TT> destructor is shown on lines 37-43.<TT>delete</TT> is called on both pointers, <TT>itsAge</TT> and <TT>itsWeight</TT>,returning the allocated memory to the free store. Also, for safety, the pointersare reassigned to <TT>NULL</TT>.<H4 ALIGN="CENTER"><A NAME="Heading23"></A><FONT COLOR="#000077">Operator Overloading</FONT></H4><P>C++ has a number of built-in types, including <TT>int</TT>, <TT>real</TT>, <TT>char</TT>,and so forth. Each of these has a number of built-in operators, such as addition(<TT>+</TT>) and multiplication (<TT>*</TT>). C++ enables you to add these operatorsto your own classes as well.</P><P>In order to explore operator overloading fully, Listing 10.6 creates a new class,<TT>Counter</TT>. A <TT>Counter</TT> object will be used in counting (surprise!)in loops and other applications where a number must be incremented, decremented,or otherwise tracked.</P><P><A NAME="Heading24"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 10.6. The Counterclass.</B></FONT></P><PRE><FONT COLOR="#0066FF">1: // Listing 10.62: // The Counter class3:4: typedef unsigned short USHORT;5: #include <iostream.h>6:7: class Counter8: {9: public:10: Counter();11: ~Counter(){}12: USHORT GetItsVal()const { return itsVal; }13: void SetItsVal(USHORT x) {itsVal = x; }14:15: private:16: USHORT itsVal;17:18: };19:20: Counter::Counter():21: itsVal(0)22: {};23:24: int main()25: {26: Counter i;27: cout << "The value of i is " << i.GetItsVal() << endl;28: return 0;<TT>29: }</TT>Output: The value of i is 0</FONT></PRE><P><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B>As it stands, this is a prettyuseless class. It is defined on lines 7-18. Its only member variable is a <TT>USHORT</TT>.The default constructor, which is declared on line 10 and whose implementation ison line 20, initializes the one member variable, <TT>itsVal</TT>, to zero.<BR><BR>Unlike an honest, red-blooded <TT>USHORT</TT>, the <TT>Counter</TT> object cannotbe incremented, decremented, added, assigned, or otherwise manipulated. In exchangefor this, it makes printing its value far more difficult!<H4 ALIGN="CENTER"><A NAME="Heading26"></A><FONT COLOR="#000077">Writing an IncrementFunction</FONT></H4><P>Operator overloading restores much of the functionality that has been strippedout of this class. For example, there are two ways to add the ability to incrementa <TT>Counter</TT> object. The first is to write an increment method, as shown inListing 10.7.</P><P><A NAME="Heading27"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 10.7. Addingan increment operator.</B></FONT></P><PRE><FONT COLOR="#0066FF">1: // Listing 10.72: // The Counter class3:4: typedef unsigned short USHORT;5: #include <iostream.h>6:7: class Counter8: {9: public:10: Counter();11: ~Counter(){}12: USHORT GetItsVal()const { return itsVal; }13: void SetItsVal(USHORT x) {itsVal = x; }14: void Increment() { ++itsVal; }15:16: private:17: USHORT itsVal;18:19: };20:21: Counter::Counter():22: itsVal(0)23: {};24:25: int main()26: {27: Counter i;28: cout << "The value of i is " << i.GetItsVal() << endl;29: i.Increment();30: cout << "The value of i is " << i.GetItsVal() << endl;31: return 0;<TT>32: }</TT></FONT></PRE><PRE><FONT COLOR="#0066FF">Output: The value of i is 0The value of i is 1</FONT></PRE><P><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B>Listing 10.7 adds an <TT>Increment</TT>function, defined on line 14. Although this works, it is cumbersome to use. The programcries out for the ability to add a <TT>++</TT> operator, and of course this can bedone.<H4 ALIGN="CENTER"><A NAME="Heading29"></A><FONT COLOR="#000077">Overloading thePrefix Operator</FONT></H4><P>Prefix operators can be overloaded by declaring functions with the form:</P><PRE><FONT COLOR="#0066FF">returnType Operator op (parameters)</FONT></PRE><P>Here, <TT>op</TT> is the operator to overload. Thus, the <TT>++</TT> operatorcan be overloaded with the following syntax:</P><PRE><FONT COLOR="#0066FF">void operator++ ()</FONT></PRE><P>Listing 10.8 demonstrates this alternative.</P><P><A NAME="Heading30"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 10.8. Overloadingoperator++.</B></FONT></P><PRE><FONT COLOR="#0066FF">1: // Listing 10.82: // The Counter class3:4: typedef unsigned short USHORT;5: #include <iostream.h>6:7: class Counter8: {9: public:10: Counter();11: ~Counter(){}12: USHORT GetItsVal()const { return itsVal; }13: void SetItsVal(USHORT x) {itsVal = x; }14: void Increment() { ++itsVal; }15: void operator++ () { ++itsVal; }16:17: private:18: USHORT itsVal;19:20: };21:22: Counter::Counter():23: itsVal(0)24: {};25:26: int main()27: {28: Counter i;29: cout << "The value of i is " << i.GetItsVal() << endl;30: i.Increment();31: cout << "The value of i is " << i.GetItsVal() << endl;32: ++i;33: cout << "The value of i is " << i.GetItsVal() << endl;34: return 0;<TT>35: }</TT>Output: The value of i is 0The value of i is 1The value of i is 2</FONT></PRE><P><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B>On line 15, <TT>operator++</TT>is overloaded, and it's used on line 32. This is far closer to the syntax one wouldexpect with the <TT>Counter</TT> object. At this point, you might consider puttingin the extra abilities for which <TT>Counter</TT> was created in the first place,such as detecting when the <TT>Counter</TT> overruns its maximum size.<BR>There is a significant defect in the way the increment operator was written, however.If you want to put the <TT>Counter</TT> on the right side of an assignment, it willfail. For example:</P><PRE><FONT COLOR="#0066FF">Counter a = ++i;</FONT></PRE><P>This code intends to create a new <TT>Counter</TT>, <TT>a</TT>, and then assignto it the value in <TT>i</TT> after <TT>i</TT> is incremented. The built-in copyconstructor will handle the assignment, but the current increment operator does notreturn a <TT>Counter</TT> object. It returns <TT>void</TT>. You can't assign a <TT>void</TT>object to a <TT>Counter</TT> object. (You can't make something from nothing!)<H4 ALIGN="CENTER"><A NAME="Heading32"></A><FONT COLOR="#000077">Returning Typesin Overloaded Operator Functions</FONT></H4><P>Clearly, what you want is to return a <TT>Counter</TT> object so that it can beassigned to another <TT>Counter</TT> object. Which object should be returned? Oneapproach would be to create a temporary object and return that. Listing 10.9 illustratesthis approach.</P><P><A NAME="Heading33"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 10.9. Returninga temporary object.</B></FONT></P><PRE><FONT COLOR="#0066FF">1: // Listing 10.92: // operator++ returns a temporary object3:4: typedef unsigned short USHORT;5: #include <iostream.h>6:7: class Counter8: {9: public:10: Counter();11: ~Counter(){}12: USHORT GetItsVal()const { return itsVal; }13: void SetItsVal(USHORT x) {itsVal = x; }14: void Increment() { ++itsVal; }15: Counter operator++ ();16:17: private:18: USHORT itsVal;19:20: };21:22: Counter::Counter():23: itsVal(0)24: {};25:26: Counter Counter::operator++()27: {28: ++itsVal;29: Counter temp;30: temp.SetItsVal(itsVal);31: return temp;32: }33:34: int main()35: {36: Counter i;37: cout << "The value of i is " << i.GetItsVal() << endl;38: i.Increment();39: cout << "The value of i is " << i.GetItsVal() << endl;40: ++i;41: cout << "The value of i is " << i.GetItsVal() << endl;42: Counter a = ++i;43: cout << "The value of a: " << a.GetItsVal();44: cout << " and i: " << i.GetItsVal() << endl;45: return 0;<TT>46: }</TT></FONT><FONT COLOR="#0066FF">Output: The value of i is 0The value of i is 1The value of i is 2The value of a: 3 and i: 3</FONT></PRE><P><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B>In this version, <TT>operator++</TT>has been declared on line 15 to return a <TT>Counter</TT> object. On line 29, a temporaryvariable, <TT>temp</TT>, is created and its value is set to match that in the currentobject. That temporary variable is returned and immediately assigned to <TT>a</TT>on line 42.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -