Absolute C++ (4th Edition) part 16 pptx

10 302 1
Absolute C++ (4th Edition) part 16 pptx

Đang tải... (xem toàn văn)

Thông tin tài liệu

152 Parameters and Overloading Now suppose your program also requires a function to compute the average of three numbers. You might define a new function called ave3 as follows: double ave3(double n1, double n2, double n3) { return ((n1 + n2 + n3)/3.0); } This will work, and in many programming languages you have no choice but to do something like this. However, C++ overloading allows for a more elegant solution. In C++ you can simply use the same function name ave for both functions. In C++ you can use the following function definition in place of the function definition ave3: double ave(double n1, double n2, double n3) { return ((n1 + n2 + n3)/3.0); } so that the function name ave then has two definitions. This is an example of overload- ing. In this case we have overloaded the function name ave. Display 4.6 embeds these two function definitions for ave into a complete sample program. Be sure to notice that each function definition has its own declaration (prototype). The compiler can tell which function definition to use by checking the number and types of the arguments in a function call. In the program in Display 4.6, one of the functions called ave has two arguments and the other has three arguments. When there are two arguments in a function call, the first definition applies. When there are three arguments in a function call, the second definition applies. Whenever you give two or more definitions to the same function name, the various function definitions must have different specifications for their arguments; that is, any two function definitions that have the same function name must use different numbers of formal parameters or have one or more parameters of different types (or both). Notice that when you overload a function name, the declarations for the two different definitions must differ in their formal parameters. You cannot overload a function name by giving two definitions that differ only in the type of the value returned. Nor can you O VERLOADING A F UNCTION N AME If you have two or more function definitions for the same function name, that is called overload- ing . When you overload a function name, the function definitions must have different numbers of formal parameters or some formal parameters of different types. When there is a function call, the compiler uses the function definition whose number of formal parameters and types of formal parameters match the arguments in the function call. determining which definition applies 04_CH04.fm Page 152 Wednesday, August 13, 2003 12:49 PM Overloading and Default Arguments 153 overload based on any difference other than the number or types of parameters. You cannot overload based solely on const or solely on call-by-value versus call-by-reference parameters. 1 1 Some compilers will, in fact, allow you to overload on the basis of const versus no const, but you should not count on this. The C++ standard says it is not allowed. D i sp l ay 4.6 Overloading a Function Name 1 //Illustrates overloading the function name ave. 2 #include <iostream> 3 using namespace std; 4 double ave(double n1, double n2); 5 //Returns the average of the two numbers n1 and n2. 6 7 double ave(double n1, double n2, double n3); 8 //Returns the average of the three numbers n1, n2, and n3. 9 int main( ) 10 { 11 cout << "The average of 2.0, 2.5, and 3.0 is " 12 << ave(2.0, 2.5, 3.0) << endl; 13 cout << "The average of 4.5 and 5.5 is " 14 << ave(4.5, 5.5) << endl; 15 return 0; 16 } 17 double ave(double n1, double n2) 18 { 19 return ((n1 + n2)/2.0); 20 } 21 double ave(double n1, double n2, double n3) 22 { 23 return ((n1 + n2 + n3)/3.0); 24 } S AMPLE D IALOGUE The average of 2.0, 2.5, and 3.0 is 2.5 The average of 4.5 and 5.5 is 5.0 Two arguments Three arguments 04_CH04.fm Page 153 Wednesday, August 13, 2003 12:49 PM 154 Parameters and Overloading Pitfall You already saw a kind of overloading in Chapter 1 (reviewed here) with the division operator, /. If both operands are of type int, as in 13/2, then the value returned is the result of integer division, in this case, 6. On the other hand, if one or both operands are of type double, then the value returned is the result of regular division; for example, 13/2.0 returns the value 6.5. There are two definitions for the division operator, /, and the two definitions are distinguished not by having different numbers of operands but rather by requiring operands of different types. The only difference between overload- ing of / and overloading function names is that the C++ language designers have already done the overloading of /, whereas you must program the overloading of your function names yourself. Chapter 8 discusses how to overload operators such as +, -, and so on. A UTOMATIC T YPE C ONVERSION AND O VERLOADING Suppose that the following function definition occurs in your program and that you have not overloaded the function name mpg (so this is the only definition of a function called mpg). double mpg(double miles, double gallons) //Returns miles per gallon. { return (miles/gallons); } If you call the function mpg with arguments of type int, then C++ will automatically convert any argument of type int to a value of type double. Hence, the following will output 22.5 miles per gallon to the screen: cout << mpg(45, 2) << " miles per gallon"; C++ converts the 45 to 45.0 and the 2 to 2.0 and then performs the division 45.0/2.0 to obtain the value returned, which is 22.5. If a function requires an argument of type double and you give it an argument of type int, C++ will automatically convert the int argument to a value of type double. This is so useful and nat- ural that we hardly give it a thought. However, overloading can interfere with this automatic type conversion. Let’s look at an example. S IGNATURE A function’s ss ss ii ii gg gg nn nn aa aa tt tt uu uu rr rr ee ee is the function’s name with the sequence of types in the parameter list, not including the const keyword and not including the ampersand, &. When you overload a func- tion name, the two definitions of the function name must have different signatures using this def- inition of signature. (Some authorities include the const and/or ampersand as part of the signature, but we wanted a definition that works for explaining overloading.) interaction of overloading and type conversion 04_CH04.fm Page 154 Wednesday, August 13, 2003 12:49 PM Overloading and Default Arguments 155 Self-Test Exercises Suppose you had (foolishly) overloaded the function name mpg so that your program contained the following definition of mpg as well as the one previous: int mpg(int goals, int misses) //Returns the Measure of Perfect Goals //which is computed as (goals - misses). { return (goals - misses); } In a program that contains both of these definitions for the function name mpg, the following will (unfortunately) output 43 miles per gallon (since 43 is 45 - 2): cout << mpg(45, 2) << " miles per gallon"; When C++ sees the function call mpg(45, 2), which has two arguments of type int, C++ first looks for a function definition of mpg that has two formal parameters of type int. If it finds such a function definition, C++ uses that function definition. C++ does not convert an int argument to a value of type double unless that is the only way it can find a matching function definition. The mpg example illustrates one more point about overloading: You should not use the same function name for two unrelated functions. Such careless use of function names is certain to even- tually produce confusion. 8. Suppose you have two function definitions with the following declarations: double score(double time, double distance); int score(double points); Which function definition would be used in the following function call and why would it be the one used? ( x is of type double.) double finalScore = score(x); 9. Suppose you have two function definitions with the following declarations: double theAnswer(double data1, double data2); double theAnswer(double time, int count); Which function definition would be used in the following function call and why would it be the one used? ( x and y are of type double.) x = theAnswer(y, 6.0); 04_CH04.fm Page 155 Wednesday, August 13, 2003 12:49 PM 156 Parameters and Overloading ■ RULES FOR RESOLVING OVERLOADING If you use overloading to produce two definitions of the same function name with sim- ilar (but not identical) parameter lists, then the interaction of overloading and auto- matic type conversion can be confusing. The rules that the compiler uses for resolving which of multiple overloaded definitions of a function name to apply to a given func- tion call are as follows: 1. Exact match: If the number and types of arguments exactly match a definition (with- out any automatic type conversion), then that is the definition used. 2. Match using automatic type conversion: If there is no exact match but there is a match using automatic type conversion, then that match is used. If two matches are found at stage 1 or if no matches are found at stage 1 and two matches are found at stage 2, then there is an ambiguous situation and an error message will be issued. For example, the following overloading is dubious style, but is perfectly valid: void f(int n, double m); void f(double n, int m); However, if you also have the invocation f(98, 99); then the compiler does not know which of the two int arguments to convert to a value of type double, and an error message is generated. To see how confusing and dangerous the situation can be, suppose you add the fol- lowing third overloading: void f(int n, int m); With this third overloading added, you no longer get an error message, since there is now an exact match. Obviously, such confusing overloading is to be avoided. The above two rules will work in almost all situations. In fact, if you need more pre- cise rules, you should rewrite your code to be more straightforward. However, the exact rules are even a bit more complicated. For reference value, we give the exact rules below. Some of the terms may not make sense until you read more of this book, but do not be concerned. The simple two rules given above will serve you well until you do understand the more complete rules. 1. Exact match as described earlier. 2. Matches using promotion within integer types or within floating-point types, such as short to int or float to double. (Note that bool-to-int and char-to-int conver- sions are considered promotions within integer types.) 3. Matches using other conversions of predefined types, such as int to double. 4. Matches using conversions of user-defined types (see Chapter 8). 04_CH04.fm Page 156 Wednesday, August 13, 2003 12:49 PM Overloading and Default Arguments 157 Example 5. Matches using ellipses (This is not covered in this book, and if you do not use it, it will not be an issue.) If two matches are found at the first stage that a match is found, then there is an ambig- uous situation and an error message will be issued. R EVISED P IZZA -B UYING P ROGRAM The Pizza Consumers Union has been very successful with the program that we wrote for it in Dis- play 4.5. In fact, now everybody always buys the pizza that is the best buy. One disreputable pizza parlor used to make money by fooling consumers into buying the more expensive pizza, but our program has put an end to its evil practices. However, the owners wish to continue their des- picable behavior and have come up with a new way to fool consumers. They now offer both round pizzas and rectangular pizzas. They know that the program we wrote cannot deal with rectangu- larly shaped pizzas, so they hope they can again confuse consumers. Display 4.7 is another ver- sion of our program that compares a round pizza and a rectangular pizza. Note that the function name unitPrice has been overloaded so that it applies to both round and rectangular pizzas. Display 4.7 Revised Pizza Program (part 1 of 3) 1 //Determines whether a round pizza or a rectangular pizza is the best buy. 2 #include <iostream> 3 using namespace std; 4 double unitPrice(int diameter, double price); 5 //Returns the price per square inch of a round pizza. 6 //The formal parameter named diameter is the diameter of the pizza 7 //in inches. The formal parameter named price is the price of the pizza. 8 double unitPrice(int length, int width, double price); 9 //Returns the price per square inch of a rectangular pizza 10 //with dimensions length by width inches. 11 //The formal parameter price is the price of the pizza. 12 int main( ) 13 { 14 int diameter, length, width; 15 double priceRound, unitPriceRound, 16 priceRectangular, unitPriceRectangular; 17 cout << "Welcome to the Pizza Consumers Union.\n"; 18 cout << "Enter the diameter in inches" 19 << " of a round pizza: "; 20 cin >> diameter; 21 cout << "Enter the price of a round pizza: $"; 04_CH04.fm Page 157 Wednesday, August 13, 2003 12:49 PM 158 Parameters and Overloading Display 4.7 Revised Pizza Program (part 2 of 3) 22 cin >> priceRound; 23 cout << "Enter length and width in inches\n" 24 << "of a rectangular pizza: "; 25 cin >> length >> width; 26 cout << "Enter the price of a rectangular pizza: $"; 27 cin >> priceRectangular; 28 unitPriceRectangular = 29 unitPrice(length, width, priceRectangular); 30 unitPriceRound = unitPrice(diameter, priceRound); 31 cout.setf(ios::fixed); 32 cout.setf(ios::showpoint); 33 cout.precision(2); 34 cout << endl 35 << "Round pizza: Diameter = " 36 << diameter << " inches\n" 37 << "Price = $" << priceRound 38 << " Per square inch = $" << unitPriceRound 39 << endl 40 << "Rectangular pizza: Length = " 41 << length << " inches\n" 42 << "Rectangular pizza: Width = " 43 << width << " inches\n" 44 << "Price = $" << priceRectangular 45 << " Per square inch = $" << unitPriceRectangular 46 << endl; 47 if (unitPriceRound < unitPriceRectangular) 48 cout << "The round one is the better buy.\n"; 49 else 50 cout << "The rectangular one is the better buy.\n"; 51 cout << "Buon Appetito!\n"; 52 return 0; 53 } 54 double unitPrice(int diameter, double price) 55 { 56 const double PI = 3.14159; 57 double radius, area; 58 59 radius = diameter/double(2); 60 area = PI * radius * radius; 61 return (price/area); 62 } 04_CH04.fm Page 158 Wednesday, August 13, 2003 12:49 PM Overloading and Default Arguments 159 ■ DEFAULT ARGUMENTS You can specify a default argument for one or more call-by-value parameters in a func- tion. If the corresponding argument is omitted, then it is replaced by the default argu- ment. For example, the function volume in Display 4.8 computes the volume of a box from its length, width, and height. If no height is given, the height is assumed to be 1. If neither a width nor a height is given, they are both assumed to be 1. Note that in Display 4.8 the default arguments are given in the function declaration but not in the function definition. A default argument is given the first time the func- tion is declared (or defined, if that occurs first). Subsequent declarations or a following definition should not give the default arguments again because some compilers will consider this an error even if the arguments given are consistent with the ones given previously. You may have more than one default argument, but all the default argument posi- tions must be in the rightmost positions. Thus, for the function volume in Display 4.8, we could have given default arguments for the last one, last two, or all three parameters, but any other combinations of default arguments are not allowed. Display 4.7 Revised Pizza Program (part 3 of 3) 63 double unitPrice(int length, int width, double price) 64 { 65 double area = length * width; 66 return (price/area); 67 } S AMPLE D IALOGUE Welcome to the Pizza Consumers Union. Enter the diameter in inches of a round pizza: 10 Enter the price of a round pizza: $8.50 Enter length and width in inches of a rectangular pizza: 6 4 Enter the price of a rectangular pizza: $7.55 Round pizza: Diameter = 10 inches Price = $8.50 Per square inch = $0.11 Rectangular pizza: Length = 6 inches Rectangular pizza: Width = 4 inches Price = $7.55 Per square inch = $0.31 The round one is the better buy. Buon Appetito! default argument 04_CH04.fm Page 159 Wednesday, August 13, 2003 12:49 PM 160 Parameters and Overloading If you have more than one default argument, then when the function is invoked, you must omit arguments starting from the right. For example, note that in Display 4.8 there are two default arguments. When only one argument is omitted, it is assumed to be the last argument. There is no way to omit the second argument in an invocation of volume without also omitting the third argument. Display 4.8 Default Arguments 1 2 #include <iostream> 3 using namespace std; 4 void showVolume(int length, int width = 1, int height = 1); 5 //Returns the volume of a box. 6 //If no height is given, the height is assumed to be 1. 7 //If neither height nor width is given, both are assumed to be 1. 8 int main( ) 9 { 10 showVolume(4, 6, 2); 11 showVolume(4, 6); 12 showVolume(4); 13 return 0; 14 } 15 void showVolume(int length, int width, int height) 16 { 17 cout << "Volume of a box with \n" 18 << "Length = " << length << ", Width = " << width << endl 19 << "and Height = " << height 20 << " is " << length*width*height << endl; 21 } S AMPLE D IALOGUE \ Volume of a box with Length = 4, Width = 6 and Height = 2 is 48 Volume of a box with Length = 4, Width = 6 and Height = 1 is 24 Volume of a box with Length = 4, Width = 1 and Height = 1 is 4 Default arguments A default argument should not be given a second time. 04_CH04.fm Page 160 Wednesday, August 13, 2003 12:49 PM Testing and Debugging Functions 161 Self-Test Exercises Default arguments are of limited value, but sometimes they can be used to reflect your way of thinking about arguments. Default arguments can only be used with call- by-value parameters. They do not make sense for call-by-reference parameters. Any- thing you can do with default arguments can be done using overloading, although the default argument version will probably be shorter than the overloading version. 10. This question has to do with the programming example entitled Revised Pizza-Buying Program. Suppose the evil pizza parlor that is always trying to fool customers introduces a square pizza. Can you overload the function unitPrice so that it can compute the price per square inch of a square pizza as well as the price per square inch of a round pizza? Why or why not? Testing and Debugging Functions I beheld the wretch—the miserable monster whom I had created. Mary Wollstonecraft Shelley, Frankenstein This section reviews some general guidelines for testing programs and functions. ■ THE assert MACRO An assertion is a statement that is either true or false. Assertions are used to document and check the correctness of programs. Preconditions and postconditions, which we discussed in Chapter 3, are examples of assertions. When expressed precisely and in the syntax of C++, an assertion is simply a Boolean expression. If you convert an assertion to a Boolean expression, then the predefined macro assert can be used to check whether or not your code satisfies the assertion. (A macro is very similar to an inline function and is used just like a function is used.) The assert macro is used like a void function that takes one call-by-value parame- ter of type bool. Since an assertion is just a Boolean expression, this means that the argument to assert is an assertion. When the assert macro is invoked, its assertion argument is evaluated. If it evaluates to true, then nothing happens. If the argument evaluates to false, then the program ends and an error message is issued. Thus, calls to the assert macro are a compact way to include error checks within your program. For example, the following function declaration is taken from Programming Project 3: void computeCoin(int coinValue, int& number, int& amountLeft); //Precondition: 0 < coinValue < 100; 0 <= amountLeft < 100. //Postcondition: number has been set equal to the maximum number 4.3 assertion macro 04_CH04.fm Page 161 Wednesday, August 13, 2003 12:49 PM . do something like this. However, C++ overloading allows for a more elegant solution. In C++ you can simply use the same function name ave for both functions. In C++ you can use the following function. << mpg(45, 2) << " miles per gallon"; When C++ sees the function call mpg(45, 2), which has two arguments of type int, C++ first looks for a function definition of mpg that. has two formal parameters of type int. If it finds such a function definition, C++ uses that function definition. C++ does not convert an int argument to a value of type double unless that

Ngày đăng: 04/07/2014, 05:21

Từ khóa liên quan

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan