📄 ch10.htm
字号:
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 0
The value of i is 1
The value of i is 2
The 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 temporary
variable, <TT>temp</TT>, is created and its value is set to match that in the current
object. That temporary variable is returned and immediately assigned to <TT>a</TT>
on line 42.
<H4 ALIGN="CENTER"><A NAME="Heading35"></A><FONT COLOR="#000077">Returning Nameless
Temporaries</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 constructor
as 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. Returning
a nameless temporary object.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">
1: // Listing 10.10
2: // operator++ returns a nameless temporary object
3:
4: typedef unsigned short USHORT;
5: #include <iostream.h>
6:
7: class Counter
8: {
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 0
The value of i is 1
The value of i is 2
The value of a: 3 and i: 3</FONT></PRE>
<P><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B>On line 11, a new constructor
is declared that takes a <TT>USHORT</TT>. The implementation is on lines 27-29. It
initializes <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 object
at all?" Remember that each temporary object must be constructed and later destroyed--each
one potentially an expensive operation. Also, the object <TT>i</TT> already exists
and already has the right value, so why not return it? We'll solve this problem by
using 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 has
the right value in its member variable <TT>itsVal</TT>. Listing 10.11 illustrates
returning the dereferenced <TT>this</TT> pointer and avoiding the creation of an
unneeded temporary object.</P>
<P><A NAME="Heading39"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 10.11. Returning
the this pointer.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">
1: // Listing 10.11
2: // Returning the dereferenced this pointer
3:
4: typedef unsigned short USHORT;
5: #include <iostream.h>
6:
7: class Counter
8: {
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 0
The value of i is 1
The value of i is 2
The 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 to
return the current object. This provides a <TT>Counter</TT> object to be assigned
to <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 default
copy constructor works fine.<BR>
<BR>
Note that the value returned is a <TT>Counter</TT> reference, thereby avoiding the
creation of an extra temporary object. It is a <TT>const</TT> reference because the
value should not be changed by the function using this <TT>Counter</TT>.
<H4 ALIGN="CENTER"><A NAME="Heading41"></A><FONT COLOR="#000077">Overloading the
Postfix Operator</FONT></H4>
<P>So far you've overloaded the prefix operator. What if you want to overload the
postfix increment operator? Here the compiler has a problem: How is it to differentiate
between prefix and postfix? By convention, an integer variable is supplied as a parameter
to the operator declaration. The parameter's value is ignored; it is just a signal
that this is the postfix operator.
<H4 ALIGN="CENTER"><A NAME="Heading42"></A><FONT COLOR="#000077">Difference Between
Prefix and Postfix</FONT></H4>
<P>Before we can write the postfix operator, we must understand how it is different
from the prefix operator. We reviewed this in detail on Day 4, "Expressions
and 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 return
the 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 assigned
it to <TT>a</TT>, and then we increased the value of <TT>x</TT>. If <TT>x</TT> is
an 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 return
that 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 and
not 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. Prefix
and postfix operators.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">
1: // Listing 10.12
2: // Returning the dereferenced this pointer
3:
4: typedef unsigned short USHORT;
5: #include <iostream.h>
6:
7: class Counter
8: {
9: public:
10: Counter();
11: ~Counter(){}
12: USHORT GetItsVal()const { return itsVal; }
13: void SetItsVal(USHORT x) {itsVal = x; }
14: const Counter& operator++ (); // prefix
15: const Counter operator++ (int); // postfix
16:
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 0
The value of i is 1
The value of i is 2
The value of a: 3 and i: 3
The value of a: 3 and i: 4
</FONT></PRE>
<P><FONT COLOR="#000077"><B>Analysis: </B></FONT>The postfix operator is declared
on line 15 and implemented on lines 31-36. Note that the call to the prefix operator
on line 14 does not include the flag integer (<TT>x</TT>), but is used with its normal
syntax. The postfix operator uses a flag value (<TT>x</TT>) to signal that it is
the 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 Overloading
Unary 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 integer
as 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. The
addition 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 add
them, 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 would
take 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.13
2: // Add function
3:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -