⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch10.htm

📁 vc的电子书
💻 HTM
📖 第 1 页 / 共 5 页
字号:
4:     typedef unsigned short  USHORT;
5:     #include <iostream.h>
6:
7:     class Counter
8:     {
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)
24:    {}
25:
26:    Counter::Counter():
27:    itsVal(0)
28:    {}
29:
30:    Counter Counter::Add(const Counter & rhs)
31:    {
32:       return Counter(itsVal+ rhs.GetItsVal());
33:    }
34:
35:    int main()
36:    {
37:       Counter varOne(2), varTwo(4), varThree;
38:       varThree = varOne.Add(varTwo);
39:       cout << "varOne: " << varOne.GetItsVal()<< endl;
40:       cout << "varTwo: " << varTwo.GetItsVal() << endl;
41:       cout << "varThree: " << varThree.GetItsVal() << endl;
42:
43:     return 0;
<TT>44: }</TT>
Output: varOne: 2
varTwo: 4
varThree: 6
</FONT></PRE>
<P><FONT COLOR="#0066FF"><BR>
</FONT><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B>The <TT>Add()</TT>function
is declared on line 15. It takes a constant <TT>Counter</TT> reference, which is
the number to add to the current object. It returns a <TT>Counter</TT> object, which
is the result to be assigned to the left side of the assignment statement, as shown
on line 38. That is, <TT>VarOne</TT> is the object, <TT>varTwo</TT> is the parameter
to the <TT>Add()</TT> function, and the result is assigned to <TT>VarThree</TT>.<BR>
<BR>
In order to create <TT>varThree</TT> without having to initialize a value for it,
a default constructor is required. The default constructor initializes <TT>itsVal</TT>
to <TT>0</TT>, as shown on lines 26-28. Since <TT>varOne</TT> and <TT>varTwo</TT>
need to be initialized to a non-zero value, another constructor was created, as shown
on lines 22-24. Another solution to this problem is to provide the default value
<TT>0</TT> to the constructor declared on line 11.
<H4 ALIGN="CENTER"><A NAME="Heading49"></A><FONT COLOR="#000077">Overloading operator+</FONT></H4>
<P>The <TT>Add()</TT> function itself is shown on lines 30-33. It works, but its
use is unnatural. Overloading the <TT>+</TT> operator would make for a more natural
use of the <TT>Counter</TT> class. Listing 10.14 illustrates this.</P>
<P><A NAME="Heading50"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 10.14. operator+.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">
1:     // Listing 10.14
2:     //Overload operator plus (+)
3:
4:     typedef unsigned short  USHORT;
5:     #include &lt;iostream.h&gt;
6:
7:     class Counter
8:     {
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 operator+ (const Counter &amp;);
16:    private:
17:       USHORT itsVal;
18:    };
19:
20:    Counter::Counter(USHORT initialValue):
21:    itsVal(initialValue)
22:    {}
23:
24:    Counter::Counter():
25:    itsVal(0)
26:    {}
27:
28:    Counter Counter::operator+ (const Counter &amp; rhs)
29:    {
30:       return Counter(itsVal + rhs.GetItsVal());
31:    }
32:
33:    int main()
34:    {
35:       Counter varOne(2), varTwo(4), varThree;
36:       varThree = varOne + varTwo;
37:       cout &lt;&lt; &quot;varOne: &quot; &lt;&lt; varOne.GetItsVal()&lt;&lt; endl;
38:       cout &lt;&lt; &quot;varTwo: &quot; &lt;&lt; varTwo.GetItsVal() &lt;&lt; endl;
39:       cout &lt;&lt; &quot;varThree: &quot; &lt;&lt; varThree.GetItsVal() &lt;&lt; endl;
40:
41:     return 0;
<TT>42: }</TT></FONT>
<FONT COLOR="#0066FF">
Output: varOne: 2
varTwo: 4
varThree: 6
</FONT></PRE>
<P><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B><TT>operator+</TT> is declared
on line 15 and defined on lines 28-31. Compare these with the declaration and definition
of the <TT>Add()</TT> function in the previous listing; they are nearly identical.
The syntax of their use, however, is quite different. It is more natural to say this:</P>
<PRE><FONT COLOR="#0066FF">varThree = varOne + varTwo;</FONT></PRE>
<P>than to say:</P>
<PRE><FONT COLOR="#0066FF">varThree = varOne.Add(varTwo);</FONT></PRE>
<P>Not a big change, but enough to make the program easier to use and understand.


<BLOCKQUOTE>
	<P>
<HR>
<FONT COLOR="#000077"><B>NOTE:</B></FONT><B> </B>The techniques used for overloading
	<TT>operator++</TT> can be applied to the other unary operators, such as <TT>operator-</TT>.
	
<HR>


</BLOCKQUOTE>

<H4 ALIGN="CENTER"><A NAME="Heading52"></A><FONT COLOR="#000077">Operator Overloading:
Binary Operators</FONT></H4>
<P>Binary operators are created like unary operators, except that they do take a
parameter. The parameter is a constant reference to an object of the same type. Example
1</P>
<PRE><FONT COLOR="#0066FF">Counter Counter::operator+ (const Counter &amp; rhs);</FONT></PRE>
<P>Example 2</P>
<PRE><FONT COLOR="#0066FF">Counter Counter::operator-(const Counter &amp; rhs);
</FONT></PRE>
<H4 ALIGN="CENTER"><A NAME="Heading53"></A><FONT COLOR="#000077">Issues in Operator
Overloading</FONT></H4>
<P>Overloaded operators can be member functions, as described in this chapter, or
non-member functions. The latter will be described on Day 14, &quot;Special Classes
and Functions,&quot; when we discuss <TT>friend</TT> functions.</P>
<P>The only operators that must be class members are the assignment (<TT>=</TT>),
subscript(<TT>[]</TT>), function call (<TT>()</TT>), and indirection (<TT>-&gt;</TT>)
operators.</P>
<P><TT>operator[]</TT> will be discussed tomorrow, when arrays are covered. Overloading
<TT>operator-&gt;</TT> will be discussed on Day 14, when smart pointers are discussed.
<H4 ALIGN="CENTER"><A NAME="Heading54"></A><FONT COLOR="#000077">Limitations on Operator
Overloading</FONT></H4>
<P>Operators on built-in types (such as <TT>int</TT>) cannot be overloaded. The precedence
order cannot be changed, and the arity of the operator, that is, whether it is unary
or binary, cannot be changed. You cannot make up new operators, so you cannot declare
<TT>**</TT> to be the &quot;power of&quot; operator.</P>

<DL>
	<DD>
<HR>
<FONT COLOR="#000077"><B>New Term:</B></FONT><B> </B><I>Arity</I> refers to how many
	terms are used in the operator. Some C++ operators are unary and use only one term
	(<TT>myValue++</TT>). Some operators are binary and use two terms (<TT>a+b</TT>).
	Only one operator is ternary and uses three terms. The <TT>?</TT> operator is often
	called the ternary operator, as it is the only ternary operator in C++ (<TT>a &gt;
	b ? x : y</TT>). 
<HR>

</DL>

<H4 ALIGN="CENTER"><A NAME="Heading55"></A><FONT COLOR="#000077">What to Overload</FONT></H4>
<P>Operator overloading is one of the aspects of C++ most overused and abused by
new programmers. It is tempting to create new and interesting uses for some of the
more obscure operators, but these invariably lead to code that is confusing and difficult
to read.</P>
<P>Of course, making the <TT>+</TT> operator subtract and the <TT>*</TT> operator
add can be fun, but no professional programmer would do that. The greater danger
lies in the well-intentioned but idiosyncratic use of an operator--using <TT>+</TT>
to mean concatenate a series of letters, or <TT>/</TT> to mean split a string. There
is good reason to consider these uses, but there is even better reason to proceed
with caution. Remember, the goal of overloading operators is to increase usability
and understanding.


<BLOCKQUOTE>
	<P>
<HR>
<B>DO</B> use operator overloading when it will clarify the program. <B>DON'T</B>
	create counter-intuitive operators. <B>DO </B>return an object of the class from
	overloaded operators. 
<HR>


</BLOCKQUOTE>

<H4 ALIGN="CENTER"><A NAME="Heading56"></A><FONT COLOR="#000077">The Assignment Operator</FONT></H4>
<P>The fourth and final function that is supplied by the compiler, if you don't specify
one, is the assignment operator (<TT>operator=()</TT>). This operator is called whenever
you assign to an object. For example:</P>
<PRE><FONT COLOR="#0066FF">CAT catOne(5,7);
CAT catTwo(3,4);
// ... other code here
catTwo = catOne;
</FONT></PRE>
<P>Here, <TT>catOne</TT> is created and initialized with <TT>itsAge</TT> equal to
5 and <TT>itsWeight</TT> equal to <TT>7</TT>. <TT>catTwo</TT> is then created and
assigned the values <TT>3</TT> and <TT>4</TT>.</P>
<P>After a while, <TT>catTwo</TT> is assigned the values in <TT>catOne</TT>. Two
issues are raised here: What happens if <TT>itsAge</TT> is a pointer, and what happens
to the original values in <TT>catTwo</TT>?</P>
<P>Handling member variables that store their values on the free store was discussed
earlier during the examination of the copy constructor. The same issues arise here,
as you saw illustrated in Figures 10.1 and 10.2.</P>
<P>C++ programmers differentiate between a shallow or member-wise copy on the one
hand, and a deep copy on the other. A shallow copy just copies the members, and both
objects end up pointing to the same area on the free store. A deep copy allocates
the necessary memory. This is illustrated in Figure 10.3.</P>
<P>There is an added wrinkle with the assignment operator, however. The object <TT>catTwo</TT>
already exists and has memory already allocated. That memory must be deleted if there
is to be no memory leak. But what happens if you assign <TT>catTwo</TT> to itself?</P>
<PRE><FONT COLOR="#0066FF">catTwo = catTwo;
</FONT></PRE>
<P>No one is likely to do this on purpose, but the program must be able to handle
it. More important, it is possible for this to happen by accident when references
and dereferenced pointers hide the fact that the assignment is to itself.</P>
<P>If you did not handle this problem carefully, <TT>catTwo</TT> would delete its
memory allocation. Then, when it was ready to copy in the memory from the right-hand
side of the assignment, it would have a very big problem: The memory would be gone.</P>
<P>To protect against this, your assignment operator must check to see if the right-hand
side of the assignment operator is the object itself. It does this by examining the
<TT>this</TT> pointer. Listing 10.15 shows a class with an assignment operator.</P>
<P><A NAME="Heading57"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 10.15. An assignment
operator.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">
1:      // Listing 10.15
2:      // Copy constructors
3:
4:      #include &lt;iostream.h&gt;
5:
6:      class CAT
7:      {
8:          public:
9:               CAT();                         // default constructor
10:    // copy constructor and destructor elided!
11:               int GetAge() const { return *itsAge; }
12:               int GetWeight() const { return *itsWeight; }
13:               void SetAge(int age) { *itsAge = age; }
14:               CAT operator=(const CAT &amp;);
15:
16:          private:
17:               int *itsAge;
18:               int *itsWeight;
19:     };
20:
21:     CAT::CAT()
22:     {
23:          itsAge = new int;
24:       itsWeight = new int;
25:       *itsAge = 5;
26:       *itsWeight = 9;
27:  }
28:
29:
30: CAT CAT::operator=(const CAT &amp; rhs)
31: {
32:    if (this == &amp;rhs)
33:       return *this;
34:    delete itsAge;
35:    delete itsWeight;
36:    itsAge = new int;
37:    itsWeight = new int;
38:    *itsAge = rhs.GetAge();
39:    *itsWeight = rhs.GetWeight();
40:    return *this;
41: }
42:
43:
44:     int main()
45:     {
46:          CAT frisky;
47:          cout &lt;&lt; &quot;frisky's age: &quot; &lt;&lt; frisky.GetAge() &lt;&lt; endl;
48:          cout &lt;&lt; &quot;Setting frisky to 6...\n&quot;;
49:          frisky.SetAge(6);
50:          CAT whiskers;
51:          cout &lt;&lt; &quot;whiskers' age: &quot; &lt;&lt; whiskers.GetAge() &lt;&lt; endl;
52:          cout &lt;&lt; &quot;copying frisky to whiskers...\n&quot;;
53:          whiskers = frisky;
54:          cout &lt;&lt; &quot;whiskers' age: &quot; &lt;&lt; whiskers.GetAge() &lt;&lt; endl;
55:     return 0;
<TT>56: }</TT></FONT></PRE>
<PRE><FONT COLOR="#0066FF">frisky's age: 5
Setting frisky to 6...
whiskers' age: 5
copying frisky to whiskers...
whiskers' age: 6
</FONT></PRE>
<P><FONT COLOR="#000077"><B>Output:</B></FONT><B> </B>Listing 10.15 bri

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -