📄 ch10.htm
字号:
52: for (int j = 0; j< printWidth; j++)53: {54: cout << "*";55: }56: cout << "\n";57: }58: }59:60: // Driver program to demonstrate overloaded functions61: int main()62: {63: // initialize a rectangle to 10,2064: 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 theoverloaded <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 thirdparameter, <TT>UseCurrentValue</TT>, is evaluated. If it is <TT>TRUE</TT>, the membervariables <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 othertwo parameters are completely ignored.<H3 ALIGN="CENTER"><A NAME="Heading9"></A><FONT COLOR="#000077">Choosing BetweenDefault Values and Overloaded Functions</FONT></H3><P>Listings 10.1 and 10.2 accomplish the same thing, but the overloaded functionsin Listing 10.1 are easier to understand and more natural to use. Also, if a thirdvariation 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'sa 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, "Basic Classes," if you do not explicitly declarea constructor for your class, a default constructor is created that takes no parametersand does nothing. You are free to make your own default constructor, however, thattakes no arguments but that "sets up" your object as required.</P><P>The constructor provided for you is called the "default" constructor,but by convention so is any constructor that takes no parameters. This can be a bitconfusing, 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 isnot made by the compiler. So if you want a constructor that takes no parameters andyou'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 pointof a <TT>Rectangle</TT> constructor is to make a rectangle. Before the constructorruns, 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 overloadconstructors 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 secondtakes no values and makes a default-sized rectangle. Listing 10.3 implements thisidea.</P><P><A NAME="Heading12"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 10.3. Overloadingthe constructor.</B></FONT></P><PRE><FONT COLOR="#0066FF">1: // Listing 10.32: // Overloading constructors3:4: #include <iostream.h>5:6: class Rectangle7: {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 << "Rect1 width: " << Rect1.GetWidth() << endl;35: cout << "Rect1 length: " << Rect1.GetLength() << endl;36:37: int aWidth, aLength;38: cout << "Enter a width: ";39: cin >> aWidth;40: cout << "\nEnter a length: ";41: cin >> aLength;42:43: Rectangle Rect2(aWidth, aLength);44: cout << "\nRect2 width: " << Rect2.GetWidth() << endl;45: cout << "Rect2 length: " << Rect2.GetLength() << endl;46: return 0;<TT>47: }</TT></FONT><FONT COLOR="#0066FF">Output: Rect1 width: 5Rect1 length: 10Enter a width: 20Enter a length: 50Rect2 width: 20Rect2 length: 50</FONT></PRE><P><FONT COLOR="#000077"><B>Analysis:</B></FONT><B> </B>The <TT>Rectangle</TT> classis declared on lines 6-17. Two constructors are declared: the "default constructor"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 valuesare printed on lines 34-35. On lines 37-41, the user is prompted for a width andlength, 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 ofthe constructor. Constructors, however, are invoked in two stages: the initializationstage and the body.</P><P>Most variables can be set in either stage, either by initializing in the initializationstage or by assigning in the body of the constructor. It is cleaner, and often moreefficient, to initialize member variables at the initialization stage. The followingexample shows how to initialize member variables:</P><PRE><FONT COLOR="#0066FF">CAT(): // constructor name and parametersitsAge(5), // initialization listitsWeight(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 theparentheses, write the expression to be used to initialize that member variable.If there is more than one initialization, separate each one with a comma. Listing10.4 shows the definition of the constructors from Listing 10.3, with initializationof the member variables rather than assignment.</P><P><A NAME="Heading15"></A><FONT SIZE="4" COLOR="#000077"><B>Listing 10.4. A codesnippet 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: referencesand constants. It is common to have other assignments or action statements in thebody 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 providesa default copy constructor. The copy constructor is called every time a copy of anobject is made.</P><P>When you pass an object by value, either into a function or as a function's returnvalue, 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 sameclass. It is a good idea to make it a constant reference, because the constructorwill not have to alter the object passed in. For example:</P><PRE><FONT COLOR="#0066FF">CAT(const CAT & 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 objectpassed as a parameter to the member variables of the new object. This is called amember-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 thefree 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">Figure10.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 mentionedon Day 8, "Pointers," 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 programis 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">Figure10.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 memoryas required. Once the memory is allocated, the old values can be copied into thenew 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.52: // Copy constructors3:4: #include <iostream.h>5:6: class CAT7: {8: public:9: CAT(); // default constructor10: CAT (const CAT &); // copy constructor11: ~CAT(); // destructor12: 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 & rhs)30: {31: itsAge = new int;32: itsWeight = new int;33: *itsAge = rhs.GetAge();34: *itsWeight = rhs.GetWeight();35: }36:37: CAT::~CAT()38: {39: delete itsAge;40: itsAge = 0;41: delete itsWeight;42: itsWeight = 0;43: }44:45: int main()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -