📄 ch10.htm
字号:
<H4 ALIGN="CENTER"><A NAME="Heading35"></A><FONT COLOR="#000077">Returning NamelessTemporaries</FONT></H4><P>There is really no need to name the temporary object created on line 29. If <TT>Counter</TT>had a constructor that took a value, you could simply return the result of that constructoras the return value of the increment operator. Listing 10.10 illustrates this idea.</P><P><A NAME="Heading36"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 10.10. Returninga nameless temporary object.</B></FONT></P><PRE><FONT COLOR="#0066FF">1: // Listing 10.102: // operator++ returns a nameless temporary object3:4: typedef unsigned short USHORT;5: #include <iostream.h>6:7: class Counter8: {9: public:10: Counter();11: Counter(USHORT val);12: ~Counter(){}13: USHORT GetItsVal()const { return itsVal; }14: void SetItsVal(USHORT x) {itsVal = x; }15: void Increment() { ++itsVal; }16: Counter operator++ ();17:18: private:19: USHORT itsVal;20:21: };22:23: Counter::Counter():24: itsVal(0)25: {}26:27: Counter::Counter(USHORT val):28: itsVal(val)29: {}30:31: Counter Counter::operator++()32: {33: ++itsVal;34: return Counter (itsVal);35: }36:37: int main()38: {39: Counter i;40: cout << "The value of i is " << i.GetItsVal() << endl;41: i.Increment();42: cout << "The value of i is " << i.GetItsVal() << endl;43: ++i;44: cout << "The value of i is " << i.GetItsVal() << endl;45: Counter a = ++i;46: cout << "The value of a: " << a.GetItsVal();47: cout << " and i: " << i.GetItsVal() << endl;48: return 0;<TT>49: }</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>On line 11, a new constructoris declared that takes a <TT>USHORT</TT>. The implementation is on lines 27-29. Itinitializes <TT>itsVal</TT> with the passed-in value.<BR>The implementation of <TT>operator++</TT> is now simplified. On line 33, <TT>itsVal</TT>is incremented. Then on line 34, a temporary <TT>Counter</TT> object is created,initialized to the value in <TT>itsVal</TT>, and then returned as the result of the<TT>operator++</TT>.</P><P>This is more elegant, but begs the question, "Why create a temporary objectat all?" Remember that each temporary object must be constructed and later destroyed--eachone potentially an expensive operation. Also, the object <TT>i</TT> already existsand already has the right value, so why not return it? We'll solve this problem byusing the <TT>this</TT> pointer.<H4 ALIGN="CENTER"><A NAME="Heading38"></A><FONT COLOR="#000077">Using the this Pointer</FONT></H4><P>The <TT>this</TT> pointer, as discussed yesterday, was passed to the <TT>operator++</TT>member function as to all member functions. The <TT>this</TT> pointer points to <TT>i</TT>,and if it's dereferenced it will return the object <TT>i</TT>, which already hasthe right value in its member variable <TT>itsVal</TT>. Listing 10.11 illustratesreturning the dereferenced <TT>this</TT> pointer and avoiding the creation of anunneeded temporary object.</P><P><A NAME="Heading39"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 10.11. Returningthe this pointer.</B></FONT></P><PRE><FONT COLOR="#0066FF">1: // Listing 10.112: // Returning the dereferenced this pointer3: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: const Counter& operator++ ();16:17: private:18: USHORT itsVal;19:20: };21:22: Counter::Counter():23: itsVal(0)24: {};25:26: const Counter& Counter::operator++()27: {28: ++itsVal;29: return *this;30: }31:32: int main()33: {34: Counter i;35: cout << "The value of i is " << i.GetItsVal() << endl;36: i.Increment();37: cout << "The value of i is " << i.GetItsVal() << endl;38: ++i;39: cout << "The value of i is " << i.GetItsVal() << endl;40: Counter a = ++i;41: cout << "The value of a: " << a.GetItsVal();42: cout << " and i: " << i.GetItsVal() << endl;48: return 0;<TT>49: }</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>The implementation of <TT>operator++</TT>,on lines 26-30, has been changed to dereference the <TT>this</TT> pointer and toreturn the current object. This provides a <TT>Counter</TT> object to be assignedto <TT>a</TT>. As discussed above, if the <TT>Counter</TT> object allocated memory,it would be important to override the copy constructor. In this case, the defaultcopy constructor works fine.<BR><BR>Note that the value returned is a <TT>Counter</TT> reference, thereby avoiding thecreation of an extra temporary object. It is a <TT>const</TT> reference because thevalue should not be changed by the function using this <TT>Counter</TT>.<H4 ALIGN="CENTER"><A NAME="Heading41"></A><FONT COLOR="#000077">Overloading thePostfix Operator</FONT></H4><P>So far you've overloaded the prefix operator. What if you want to overload thepostfix increment operator? Here the compiler has a problem: How is it to differentiatebetween prefix and postfix? By convention, an integer variable is supplied as a parameterto the operator declaration. The parameter's value is ignored; it is just a signalthat this is the postfix operator.<H4 ALIGN="CENTER"><A NAME="Heading42"></A><FONT COLOR="#000077">Difference BetweenPrefix and Postfix</FONT></H4><P>Before we can write the postfix operator, we must understand how it is differentfrom the prefix operator. We reviewed this in detail on Day 4, "Expressionsand Statements" (see Listing 4.3).</P><P>To review, prefix says "increment, and then fetch," while postfix says"fetch, and then increment."</P><P>Thus, while the prefix operator can simply increment the value and then returnthe object itself, the postfix must return the value that existed before it was incremented.To do this, we must create a temporary object that will hold the original value,then increment the value of the original object, and then return the temporary.</P><P>Let's go over that again. Consider the following line of code:</P><PRE><FONT COLOR="#0066FF">a = x++;</FONT></PRE><P>If <TT>x</TT> was <TT>5</TT>, after this statement <TT>a</TT> is <TT>5</TT>, but<TT>x</TT> is <TT>6</TT>. Thus, we returned the value in <TT>x</TT> and assignedit to <TT>a</TT>, and then we increased the value of <TT>x</TT>. If <TT>x</TT> isan object, its postfix increment operator must stash away the original value (<TT>5</TT>)in a temporary object, increment <TT>x</TT>'s value to <TT>6</TT>, and then returnthat temporary to assign its value to <TT>a</TT>.</P><P>Note that since we are returning the temporary, we must return it by value andnot by reference, as the temporary will go out of scope as soon as the function returns.</P><P>Listing 10.12 demonstrates the use of both the prefix and the postfix operators.</P><P><A NAME="Heading43"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 10.12. Prefixand postfix operators.</B></FONT></P><PRE><FONT COLOR="#0066FF">1: // Listing 10.122: // Returning the dereferenced this pointer3: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: const Counter& operator++ (); // prefix15: const Counter operator++ (int); // postfix16:17: private:18: USHORT itsVal;19: };20:21: Counter::Counter():22: itsVal(0)23: {}24:25: const Counter& Counter::operator++()26: {27: ++itsVal;28: return *this;29: }30:31: const Counter Counter::operator++(int)32: {33: Counter temp(*this);34: ++itsVal;35: return temp;36: }37:38: int main()39: {40: Counter i;41: cout << "The value of i is " << i.GetItsVal() << endl;42: i++;43: cout << "The value of i is " << i.GetItsVal() << endl;44: ++i;45: cout << "The value of i is " << i.GetItsVal() << endl;46: Counter a = ++i;47: cout << "The value of a: " << a.GetItsVal();48: cout << " and i: " << i.GetItsVal() << endl;49: a = i++;50: cout << "The value of a: " << a.GetItsVal();51: cout << " and i: " << i.GetItsVal() << endl;52: return 0;<TT>53: }</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: 3The value of a: 3 and i: 4</FONT></PRE><P><FONT COLOR="#000077"><B>Analysis: </B></FONT>The postfix operator is declaredon line 15 and implemented on lines 31-36. Note that the call to the prefix operatoron line 14 does not include the flag integer (<TT>x</TT>), but is used with its normalsyntax. The postfix operator uses a flag value (<TT>x</TT>) to signal that it isthe postfix and not the prefix. The flag value (<TT>x</TT>) is never used, however.<H3 ALIGN="CENTER"><A NAME="Heading45"></A><FONT COLOR="#000077">Operator OverloadingUnary Operators</FONT></H3><P>Declare an overloaded operator as you would a function. Use the keyword <TT>operator</TT>,followed by the operator to overload. Unary operator functions do not take parameters,with the exception of the postfix increment and decrement, which take an integeras a flag. Example 1</P><PRE><FONT COLOR="#0066FF">const Counter& Counter::operator++ ();</FONT></PRE><P>Example 2</P><PRE><FONT COLOR="#0066FF">Counter Counter::operator-(int);</FONT></PRE><BLOCKQUOTE> <P><HR><B>DO</B> use a parameter to <TT>operator++</TT> if you want the postfix operator.<B> DO</B> return a <TT>const</TT> reference to the object from <TT>operator++</TT>.<B> DON'T</B> create temporary objects as return values from <TT>operator++</TT>. <HR></BLOCKQUOTE><H4 ALIGN="CENTER"><A NAME="Heading46"></A><FONT COLOR="#000077">The Addition Operator</FONT></H4><P>The increment operator is a unary operator. It operates on only one object. Theaddition operator (<TT>+</TT>) is a binary operator, where two objects are involved.How do you implement overloading the <TT>+</TT> operator for <TT>Count</TT>?</P><P>The goal is to be able to declare two <TT>Counter</TT> variables and then addthem, as in this example:</P><PRE><FONT COLOR="#0066FF">Counter varOne, varTwo, varThree;VarThree = VarOne + VarTwo;</FONT></PRE><P>Once again, you could start by writing a function, <TT>Add()</TT>, which wouldtake a <TT>Counter</TT> as its argument, add the values, and then return a <TT>Counter</TT>with the result. Listing 10.13 illustrates this approach.</P><P><A NAME="Heading47"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 10.13. The Add()function.</B></FONT></P><PRE><FONT COLOR="#0066FF">1: // Listing 10.132: // Add function3:4: typedef unsigned short USHORT;5: #include <iostream.h>6:7: class Counter8: {9: public:10: Counter();11: Counter(USHORT initialValue);12: ~Counter(){}13: USHORT GetItsVal()const { return itsVal; }14: void SetItsVal(USHORT x) {itsVal = x; }15: Counter Add(const Counter &);16:17: private:18: USHORT itsVal;19:20: };21:22: Counter::Counter(USHORT initialValue):23: itsVal(initialValue)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -