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

📄 ch10.htm

📁 vc的电子书
💻 HTM
📖 第 1 页 / 共 5 页
字号:
47:       }
48:
49:
50:       for (int i = 0; i<printHeight; i++)
51:       {
52:          for (int j = 0; j< printWidth; j++)
53:          {
54:             cout << "*";
55:          }
56:          cout << "\n";
57:       }
58:    }
59:
60:    // Driver program to demonstrate overloaded functions
61:    int main()
62:    {
63:       // initialize a rectangle to 10,20
64:       Rectangle theRect(30,5);
65:       cout << "DrawShape(0,0,TRUE)...\n";
66:       theRect.DrawShape(0,0,TRUE);
67:       cout <<"DrawShape(40,2)...\n";
68:       theRect.DrawShape(40,2);
69:     return 0;
<TT>70: }</TT></FONT>
<FONT COLOR="#0066FF">
Output: DrawShape(0,0,TRUE)...
******************************
******************************
******************************
******************************
******************************
DrawShape(40,2)...
************************************************************
************************************************************
</FONT></PRE>
<P><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B>Listing 10.2 replaces the
overloaded <TT>DrawShape()</TT> function with a single function with default parameters.
The function is declared on line 14 to take three parameters. The first two, <TT>aWidth</TT>
and <TT>aHeight</TT>, are <TT>USHORT</TT>s, and the third, <TT>UseCurrentVals</TT>,
is a <TT>BOOL</TT> (true or false) that defaults to <TT>FALSE</TT>.


<BLOCKQUOTE>
	<P>
<HR>
<FONT COLOR="#000077"><B>NOTE:</B></FONT><B> </B>Boolean values are those that evaluate
	to <TT>TRUE</TT> or <TT>FALSE</TT>. C++ considers 0 to be false and all other values
	to be true. 
<HR>


</BLOCKQUOTE>

<P>The implementation for this somewhat awkward function begins on line 29. The third
parameter, <TT>UseCurrentValue</TT>, is evaluated. If it is <TT>TRUE</TT>, the member
variables <TT>itsWidth</TT> and <TT>itsHeight</TT> are used to set the local variables
<TT>printWidth</TT> and <TT>printHeight</TT>, respectively.</P>
<P>If <TT>UseCurrentValue</TT> is <TT>FALSE</TT>, either because it has defaulted
<TT>FALSE</TT> or was set by the user, the first two parameters are used for setting
<TT>printWidth</TT> and <TT>printHeight</TT>.</P>
<P>Note that if <TT>UseCurrentValue</TT> is <TT>TRUE</TT>, the values of the other
two parameters are completely ignored.
<H3 ALIGN="CENTER"><A NAME="Heading9"></A><FONT COLOR="#000077">Choosing Between
Default Values and Overloaded Functions</FONT></H3>
<P>Listings 10.1 and 10.2 accomplish the same thing, but the overloaded functions
in Listing 10.1 are easier to understand and more natural to use. Also, if a third
variation is needed--perhaps the user wants to supply either the width or the height,
but not both--it is easy to extend the overloaded functions. The default value, however,
will quickly become unusably complex as new variations are added.</P>
<P>How do you decide whether to use function overloading or default values? Here's
a rule of thumb:</P>
<P>Use function overloading when

<UL>
	<LI>There is no reasonable default value.
	<P>
	<LI>You need different algorithms.
	<P>
	<LI>You need to support variant types in your parameter list.
</UL>

<H3 ALIGN="CENTER"><A NAME="Heading10"></A><FONT COLOR="#000077">The Default Constructor</FONT></H3>
<P>As discussed on Day 6, &quot;Basic Classes,&quot; if you do not explicitly declare
a constructor for your class, a default constructor is created that takes no parameters
and does nothing. You are free to make your own default constructor, however, that
takes no arguments but that &quot;sets up&quot; your object as required.</P>
<P>The constructor provided for you is called the &quot;default&quot; constructor,
but by convention so is any constructor that takes no parameters. This can be a bit
confusing, but it is usually clear from context which is meant.</P>
<P>Take note that if you make any constructors at all, the default constructor is
not made by the compiler. So if you want a constructor that takes no parameters and
you've created any other constructors, you must make the default constructor yourself!
<H3 ALIGN="CENTER"><A NAME="Heading11"></A><FONT COLOR="#000077">Overloading Constructors</FONT></H3>
<P>The point of a constructor is to establish the object; for example, the point
of a <TT>Rectangle</TT> constructor is to make a rectangle. Before the constructor
runs, there is no rectangle, just an area of memory. After the constructor finishes,
there is a complete, ready-to-use <TT>rectangle</TT> object.</P>
<P>Constructors, like all member functions, can be overloaded. The ability to overload
constructors is very powerful and very flexible.</P>
<P>For example, you might have a <TT>rectangle</TT> object that has two constructors:
The first takes a length and a width and makes a rectangle of that size. The second
takes no values and makes a default-sized rectangle. Listing 10.3 implements this
idea.</P>
<P><A NAME="Heading12"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 10.3. Overloading
the constructor.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">
1:     // Listing 10.3
2:      // Overloading constructors
3:
4:      #include &lt;iostream.h&gt;
5:
6:      class Rectangle
7:      {
8:      public:
9:           Rectangle();
10:           Rectangle(int width, int length);
11:           ~Rectangle() {}
12:           int GetWidth() const { return itsWidth; }
13:           int GetLength() const { return itsLength; }
14:      private:
15:           int itsWidth;
16:           int itsLength;
17:      };
18:
19:      Rectangle::Rectangle()
20:      {
21:           itsWidth = 5;
22:           itsLength = 10;
23:      }
24:
25:      Rectangle::Rectangle (int width, int length)
26:      {
27:           itsWidth = width;
28:           itsLength = length;
29:      }
30:
31:      int main()
32:      {
33:           Rectangle Rect1;
34:           cout &lt;&lt; &quot;Rect1 width: &quot; &lt;&lt; Rect1.GetWidth() &lt;&lt; endl;
35:           cout &lt;&lt; &quot;Rect1 length: &quot; &lt;&lt; Rect1.GetLength() &lt;&lt; endl;
36:
37:           int aWidth, aLength;
38:           cout &lt;&lt; &quot;Enter a width: &quot;;
39:           cin &gt;&gt; aWidth;
40:           cout &lt;&lt; &quot;\nEnter a length: &quot;;
41:           cin &gt;&gt; aLength;
42:
43:           Rectangle Rect2(aWidth, aLength);
44:           cout &lt;&lt; &quot;\nRect2 width: &quot; &lt;&lt; Rect2.GetWidth() &lt;&lt; endl;
45:           cout &lt;&lt; &quot;Rect2 length: &quot; &lt;&lt; Rect2.GetLength() &lt;&lt; endl;
46:     return 0;
<TT>47: }</TT></FONT>
<FONT COLOR="#0066FF">
Output: Rect1 width: 5
Rect1 length: 10
Enter a width: 20

Enter a length: 50

Rect2 width: 20
Rect2 length: 50
</FONT></PRE>
<P><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B>The <TT>Rectangle</TT> class
is declared on lines 6-17. Two constructors are declared: the &quot;default constructor&quot;
on line 9 and a constructor taking two integer variables.<BR>
<BR>
On line 33, a rectangle is created using the default constructor, and its values
are printed on lines 34-35. On lines 37-41, the user is prompted for a width and
length, and the constructor taking two parameters is called on line 43. Finally,
the width and height for this rectangle are printed on lines 44-45.</P>
<P>Just as it does any overloaded function, the compiler chooses the right constructor,
based on the number and type of the parameters.
<H3 ALIGN="CENTER"><A NAME="Heading14"></A><FONT COLOR="#000077">Initializing Objects</FONT></H3>
<P>Up to now, you've been setting the member variables of objects in the body of
the constructor. Constructors, however, are invoked in two stages: the initialization
stage and the body.</P>
<P>Most variables can be set in either stage, either by initializing in the initialization
stage or by assigning in the body of the constructor. It is cleaner, and often more
efficient, to initialize member variables at the initialization stage. The following
example shows how to initialize member variables:</P>
<PRE><FONT COLOR="#0066FF">CAT():        // constructor name and parameters
itsAge(5),    // initialization list
itsWeight(8)
{ }                // body of constructor
</FONT></PRE>
<P>After the closing parentheses on the constructor's parameter list, write a colon.
Then write the name of the member variable and a pair of parentheses. Inside the
parentheses, write the expression to be used to initialize that member variable.
If there is more than one initialization, separate each one with a comma. Listing
10.4 shows the definition of the constructors from Listing 10.3, with initialization
of the member variables rather than assignment.</P>
<P><A NAME="Heading15"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 10.4. A code
snippet showing initialization of member variables.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">
1:   Rectangle::Rectangle():
2:       itsWidth(5),
3:       itsLength(10)
4:   {
5:   };
6:
7:   Rectangle::Rectangle (int width, int length)
8:       itsWidth(width),
9:       itsLength(length)
10:  
<TT>11: };</TT> 

</FONT><FONT COLOR="#000000"><B>Output: </B>No output</FONT><FONT COLOR="#0066FF">.</FONT></PRE>
<P>There are some variables that must be initialized and cannot be assigned to: references
and constants. It is common to have other assignments or action statements in the
body of the constructor; however, it is best to use initialization as much as possible.
<H3 ALIGN="CENTER"><A NAME="Heading17"></A><FONT COLOR="#000077">The Copy Constructor</FONT></H3>
<P>In addition to providing a default constructor and destructor, the compiler provides
a default copy constructor. The copy constructor is called every time a copy of an
object is made.</P>
<P>When you pass an object by value, either into a function or as a function's return
value, a temporary copy of that object is made. If the object is a user-defined object,
the class's copy constructor is called, as you saw yesterday in Listing 9.6.</P>
<P>All copy constructors take one parameter, a reference to an object of the same
class. It is a good idea to make it a constant reference, because the constructor
will not have to alter the object passed in. For example:</P>
<PRE><FONT COLOR="#0066FF">CAT(const CAT &amp; theCat);
</FONT></PRE>
<P>Here the <TT>CAT</TT> constructor takes a constant reference to an existing <TT>CAT</TT>
object. The goal of the copy constructor is to make a copy of <TT>theCAT</TT>.</P>
<P>The default copy constructor simply copies each member variable from the object
passed as a parameter to the member variables of the new object. This is called a
member-wise (or shallow) copy, and although this is fine for most member variables,
it breaks pretty quickly for member variables that are pointers to objects on the
free store.</P>

<DL>
	<DD>
<HR>
<FONT COLOR="#000077"><B>New Term:</B></FONT><B> </B>A <I>shallow</I> or <I>member-wise</I>
	copy copies the exact values of one object's member variables into another object.
	Pointers in both objects end up pointing to the same memory. A deep copy copies the
	values allocated on the heap to newly allocated memory.
	<P>If the <TT>CAT</TT> class includes a member variable, <TT>itsAge</TT>, that points
	to an integer on the free store, the default copy constructor will copy the passed-in
	<TT>CAT</TT>'s <TT>itsAge</TT> member variable to the new <TT>CAT</TT>'s <TT>itsAge</TT>
	member variable. The two objects will now point to the same memory, as illustrated
	in Figure 10.1. 
<HR>

</DL>

<P><A NAME="Heading18"></A><A HREF="102cp01.jpg" tppabs="http://www.mcp.com/814147200/0-672/0-672-31070-8/art/ch10/102cp01.jpg"><FONT COLOR="#000077">Figure
10.1.</FONT></A><I>Using the default copy constructor.</I><BR>
<BR>
This will lead to a disaster when either <TT>CAT</TT> goes out of scope. As mentioned
on Day 8, &quot;Pointers,&quot; the job of the destructor is to clean up this memory.
If the original <TT>CAT</TT>'s destructor frees this memory and the new <TT>CAT</TT>
is still pointing to the memory, a stray pointer has been created, and the program
is in mortal danger. Figure 10.2 illustrates this problem.<BR>
<BR>
<A NAME="Heading19"></A><A HREF="tppmsgs/msgs0.htm#4" tppabs="http://www.mcp.com/814147200/0-672/0-672-31070-8/art/ch10/102cp02.jpg"><FONT COLOR="#000077">Figure
10.2.</FONT></A><FONT COLOR="#000077"> </FONT><I>Creating a stray pointer.</I><BR>
<BR>
The solution to this is to create your own copy constructor and to allocate the memory
as required. Once the memory is allocated, the old values can be copied into the
new memory. This is called a deep copy. Listing 10.5 illustrates how to do this.</P>
<P><A NAME="Heading20"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 10.5. Copy constructors.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">
1:   // Listing 10.5
2:   // Copy constructors
3:
4:   #include &lt;iostream.h&gt;
5:
6:   class CAT
7:   {
8:       public:
9:            CAT();                         // default constructor
10:            CAT (const CAT &amp;);     // copy constructor
11:            ~CAT();                         // destructor
12:            int GetAge() const { return *itsAge; }
13:            int GetWeight() const { return *itsWeight; }
14:            void SetAge(int age) { *itsAge = age; }
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:  CAT::CAT(const CAT &amp; rhs)
30:  {
31:       itsAge = new int;
32:       itsWeight = new int;
33:       *itsAge = rhs.GetAge();
34:       *itsWeight = rhs.GetWeight();
35:  }

⌨️ 快捷键说明

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