Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 40 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
40
Dung lượng
547,12 KB
Nội dung
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 162 Parameters and Overloading //of coins of denomination coinValue cents that can be obtained //from amountLeft cents. amountLeft has been decreased by the //value of the coins, that is, decreased by number*coinValue. You can check that the precondition holds for a function invocation, as shown by the following example: assert((0 < currentCoin) && (currentCoin < 100) && (0 <= currentAmountLeft) && (currentAmountLeft < 100)); computeCoin(currentCoin, number, currentAmountLeft); If the precondition is not satisfied, your program will end and an error message will be output. The assert macro is defined in the library cassert, so any program that uses the assert macro must contain the following: #include <cassert> One advantage of using assert is that you can turn assert invocations off. You can use assert invocations in your program to debug your program, and then turn them off so that users do not get error messages that they might not understand. Doing so reduces the overhead performed by your program. To turn off all the # define NDEBUG assertions in your program, add #define NDEBUG before the include directive, as follows: #define NDEBUG #include <cassert> Thus, if you insert #define NDEBUG in your program after it is fully debugged, all assert invocations in your program will be turned off. If you later change your pro- gram and need to debug it again, you can turn the assert invocations back on by deleting the #define NDEBUG line (or commenting it out). Not all comment assertions can easily be translated into C++ Boolean expressions. Preconditions are more likely to translate easily than postconditions are. Thus, the assert macro is not a cure-all for debugging your functions, but it can be very useful. ■ STUBS AND DRIVERS Each function should be designed, coded, and tested as a separate unit from the rest of the program. When you treat each function as a separate unit, you transform one big task into a series of smaller, more manageable tasks. But how do you test a function outside the program for which it is intended? One way is to write a special program to do the testing. For example, Display 4.9 shows a program to test the function unit- Price that was used in the program in Display 4.5. Programs like this one are called driver programs. These driver programs are temporary tools and can be quite mini- mal. They need not have fancy input routines. They need not perform all the calcula- tions the final program will perform. All they need do is obtain reasonable values for turning off assert #define NDEBUG driver program 04_CH04.fm Page 162 Wednesday, August 13, 2003 12:49 PM Testing and Debugging Functions 163 Display 4.9 Driver Program (part 1 of 2) 1 2 //Driver program for the function unitPrice. 3 #include <iostream> 4 using namespace std; 5 double unitPrice(int diameter, double price); 6 //Returns the price per square inch of a pizza. 7 //Precondition: The diameter parameter is the diameter of the pizza 8 //in inches. The price parameter is the price of the pizza. 9 int main( ) 10 { 11 double diameter, price; 12 char ans; 13 do 14 { 15 cout << "Enter diameter and price:\n"; 16 cin >> diameter >> price; 17 cout << "unit Price is $" 18 << unitPrice(diameter, price) << endl; 19 cout << "Test again? (y/n)"; 20 cin >> ans; 21 cout << endl; 22 } while (ans == ’y’ || ans == ’Y’); 23 return 0; 24 } 25 26 double unitPrice(int diameter, double price) 27 { 28 const double PI = 3.14159; 29 double radius, area; 30 radius = diameter/static_cast<double>(2); 31 area = PI * radius * radius; 32 return (price/area); 33 } 04_CH04.fm Page 163 Wednesday, August 13, 2003 12:49 PM 164 Parameters and Overloading the function arguments in as simple a way as possible—typically from the user—then execute the function and show the result. A loop, as in the program shown in Display 4.9, will allow you to retest the function on different arguments without having to rerun the program. If you test each function separately, you will find most of the mistakes in your pro- gram. Moreover, you will find out which functions contain the mistakes. If you were to test only the entire program, you would probably find out if there were a mistake, but you may have no idea where the mistake is. Even worse, you may think you know where the mistake is, but be wrong. Once you have fully tested a function, you can use it in the driver program for some other function. Each function should be tested in a program in which it is the only untested function. However, it’s fine to use a fully tested function when testing some other function. If a bug is found, you know the bug is in the untested function. It is sometimes impossible or inconvenient to test a function without using some other function that has not yet been written or has not yet been tested. In this case, you can use a simplified version of the missing or untested function. These simplified func- tions are called stubs. These stubs will not necessarily perform the correct calculation, but they will deliver values that suffice for testing, and they are simple enough that you can have confidence in their performance. For example, the following is a possible stub for the function unitPrice: //A stub. The final function definition must still be written. double unitPrice(int diameter, double price) { return (9.99);//Not correct but good enough for a stub. } Using a program outline with stubs allows you to test and then flesh out the basic program outline, rather than write a completely new program to test each function. For Display 4.9 Driver Program (part 2 of 2) S AMPLE D IALOGUE \ Enter diameter and price: 13 14.75 Unit price is: $0.111126 Test again? (y/n): y Enter diameter and price: 2 3.15 Unit price is: $1.00268 Test again? (y/n): n stub 04_CH04.fm Page 164 Wednesday, August 13, 2003 12:49 PM Chapter Summary 165 Self-Test Exercises this reason, a program outline with stubs is usually the most efficient method of test- ing. A common approach is to use driver programs to test some basic functions, such as input and output, and then use a program with stubs to test the remaining functions. The stubs are replaced by functions one at a time: One stub is replaced by a complete function and tested; once that function is fully tested, another stub is replaced by a full function definition, and so forth, until the final program is produced. 11. What is the fundamental rule for testing functions? Why is this a good way to test functions? 12. What is a driver program? 13. What is a stub? 14. Write a stub for the function whose declaration is given below. Do not write a whole pro- gram, only the stub that would go in a program. ( Hint: It will be very short.) double rainProb(double pressure, double humidity, double temp); //Precondition: pressure is the barometric pressure in inches of mercury, //humidity is the relative humidity as a percentage, and //temp is the temperature in degrees Fahrenheit. //Returns the probability of rain, which is a number between 0 and 1. //0 means no chance of rain. 1 means rain is 100% certain ) ■ A formal parameter is a kind of placeholder that is filled in with a function argu- ment when the function is called. In C++, there are two methods of performing this substitution, call by value and call by reference, and so there are two basic kinds of parameters: call-by-value parameters and call-by-reference parameters. ■ A call-by-value formal parameter is a local variable that is initialized to the value of its corresponding argument when the function is called. Occasionally, it is useful to use a formal call-by-value parameter as a local variable. ■ In the call-by-reference substitution mechanism, the argument should be a variable, and the entire variable is substituted for the corresponding argument. T HE F UNDAMENTAL R ULE FOR T ESTING F UNCTIONS Every function should be tested in a program in which every other function in that program has already been fully tested and debugged. Chapter Summary 04_CH04.fm Page 165 Wednesday, August 13, 2003 12:49 PM 166 Parameters and Overloading ■ The way to indicate a call-by-reference parameter in a function definition is to attach the ampersand sign, &, to the type of the formal parameter. (A call-by-value parameter is indicated by the absence of an ampersand.) ■ An argument corresponding to a call-by-value parameter cannot be changed by a function call. An argument corresponding to a call-by-reference parameter can be changed by a function call. If you want a function to change the value of a variable, then you must use a call-by-reference parameter. ■ You can give multiple definitions to the same function name, provided that the dif- ferent functions with the same name have different numbers of parameters or some parameter position with differing types, or both. This is called overloading the func- tion name. ■ You can specify a default argument for one or more call-by-value parameters in a function. Default arguments are always in the rightmost argument positions. ■ The assert macro can be used to help debug your program by checking whether or not assertions hold. ■ Every function should be tested in a program in which every other function in that program has already been fully tested and debugged. ANSWERS TO SELF-TEST EXERCISES 1. A call-by-value parameter is a local variable. When the function is invoked, the value of a call- by-value argument is computed and the corresponding call-by-value parameter (which is a local variable) is initialized to this value. 2. The function will work fine. That is the entire answer, but here is some additional informa- tion: The formal parameter inches is a call-by-value parameter and, as discussed in the text, is therefore a local variable. Thus, the value of the argument will not be changed. 3. 10 20 30 1 2 3 1 20 3 4. Enter two integers: 5 10 In reverse order the numbers are: 5 5 5. void zeroBoth(int& n1, int& n2) { n1 = 0; n2 = 0; } 04_CH04.fm Page 166 Wednesday, August 13, 2003 12:49 PM Answers to Self-Test Exercises 167 6. void addTax(double taxRate, double& cost) { cost = cost + (taxRate/100.0)*cost; } The division by 100 is to convert a percentage to a fraction. For example, 10% is 10/100.0, or one-tenth of the cost. 7. par1Value in function call = 111 par2Ref in function call = 222 n1 after function call = 1 n2 after function call = 2 8. The one with one parameter would be used because the function call has only one parameter. 9. The first one would be used because it is an exact match, namely, two parameters of type double. 10. This cannot be done (at least not in any nice way). The natural ways to represent a square and a round pizza are the same. Each is naturally represented as one number, which is the radius for a round pizza and the length of a side for a square pizza. In either case the func- tion unitPrice would need to have one formal parameter of type double for the price and one formal parameter of type int for the size (either radius or side). Thus, the two function declarations would have the same number and types of formal parameters. (Spe- cifically, they would both have one formal parameter of type double and one formal parameter of type int.) Thus, the compiler would not be able to decide which definition to use. You can still defeat this evil pizza parlor’s strategy by defining two functions, but they will need to have different names. 11. The fundamental rule for testing functions is that every function should be tested in a pro- gram in which every other function in that program has already been fully tested and debugged. This is a good way to test a function because if you follow this rule, then when you find a bug, you will know which function contains the bug. 12. A driver program is a program written for the sole purpose of testing a function. 13. A stub is a simplified version of a function that is used in place of the function so that other functions can be tested. 14. //THIS IS JUST A STUB. double rainProb(double pressure, double humidity, double temp) { return 0.25; //Not correct, //but good enough for some testing. } Different 04_CH04.fm Page 167 Wednesday, August 13, 2003 12:49 PM 168 Parameters and Overloading PROGRAMMING PROJECTS 1. Write a program that converts from 24-hour notation to 12-hour notation. For example, it should convert 14:25 to 2:25 P.M. The input is given as two integers. There should be at least three functions: one for input, one to do the conversion, and one for output. Record the A.M./P.M. information as a value of type char, ’A’ for A.M. and ’P’ for P.M. Thus, the function for doing the conversions will have a call-by-reference formal parameter of type char to record whether it is A.M. or P.M. (The function will have other parameters as well.) Include a loop that lets the user repeat this computation for new input values again and again until the user says he or she wants to end the program. 2. The area of an arbitrary triangle can be computed using the formula where a, b, and c are the lengths of the sides, and s is the semiperimeter. Write a void function that uses five parameters: three value parameters that provide the lengths of the edges, and two reference parameters that compute the area and perimeter (not the semiperimeter). Make your function robust. Note that not all combinations of a, b, and c produce a triangle. Your function should produce correct results for legal data and reasonable results for illegal combinations. 3. Write a program that tells what coins to give out for any amount of change from 1 cent to 99 cents. For example, if the amount is 86 cents, the output would be something like the following: 86 cents can be given as 3 quarter(s) 1 dime(s) and 1 penny(pennies) Use coin denominations of 25 cents (quarters), 10 cents (dimes), and 1 cent (pennies). Do not use nickel and half-dollar coins. Your program will use the following function (among others): 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 //of coins of denomination coinValue cents that can be obtained //from amountLeft cents. amountLeft has been decreased by the //value of the coins, that is, decreased by number*coinValue. For example, suppose the value of the variable amountLeft is 86. Then, after the following call, the value of number will be 3 and the value of amountLeft will be 11 (because if you take three quarters from 86 cents, that leaves 11 cents): computeCoins(25, number, amountLeft); area s s a–()sb–()sc–()= sabc++()2⁄= 04_CH04.fm Page 168 Wednesday, August 13, 2003 12:49 PM Programming Projects 169 Include a loop that lets the user repeat this computation for new input values until the user says he or she wants to end the program. (Hint: Use integer division and the % operator to implement this function.) 4. Write a program that will read in a length in feet and inches and output the equivalent length in meters and centimeters. Use at least three functions: one for input, one or more for calculating, and one for output. Include a loop that lets the user repeat this computa- tion for new input values until the user says he or she wants to end the program. There are 0.3048 meters in a foot, 100 centimeters in a meter, and 12 inches in a foot. 5. Write a program like that of the previous exercise that converts from meters and centime- ters into feet and inches. Use functions for the subtasks. 6. (You should do the previous two programming projects before doing this one.) Write a program that combines the functions in the previous two programming projects. The pro- gram asks the user if he or she wants to convert from feet and inches to meters and centi- meters or from meters and centimeters to feet and inches. The program then performs the desired conversion. Have the user respond by typing the integer 1 for one type of conver- sion and 2 for the other conversion. The program reads the user’s answer and then executes an if-else statement. Each branch of the if-else statement will be a function call. The two functions called in the if-else statement will have function definitions that are very similar to the programs for the previous two programming projects. Thus, they will be fairly complicated function definitions that call other functions. Include a loop that lets the user repeat this computation for new input values until the user says he or she wants to end the program. 7. Write a program that will read in a weight in pounds and ounces and will output the equiv- alent weight in kilograms and grams. Use at least three functions: one for input, one or more for calculating, and one for output. Include a loop that lets the user repeat this com- putation for new input values until the user says he or she wants to end the program. There are 2.2046 pounds in a kilogram, 1000 grams in a kilogram, and 16 ounces in a pound. 8. Write a program like that of the previous exercise that converts from kilograms and grams into pounds and ounces. Use functions for the subtasks. 9. (You should do the previous two programming projects before doing this one.) Write a program that combines the functions of the previous two programming projects. The pro- gram asks the user if he or she wants to convert from pounds and ounces to kilograms and grams or from kilograms and grams to pounds and ounces. The program then performs the desired conversion. Have the user respond by typing the integer 1 for one type of conver- sion and 2 for the other. The program reads the user’s answer and then executes an if- else statement. Each branch of the if-else statement will be a function call. The two functions called in the if-else statement will have function definitions that are very simi- lar to the programs for the previous two programming projects. Thus, they will be fairly complicated function definitions that call other functions in their function bodies. Include a loop that lets the user repeat this computation for new input values until the user says he or she wants to end the program. 04_CH04.fm Page 169 Wednesday, August 13, 2003 12:49 PM [...]... Functions 181 9 Write some C++ code that will fill an array a with 20 values of type int read in from the keyboard You need not write a full program, just the code to do this, but do give the declarations for the array and for all variables 10 Suppose you have the following array declaration in your program: int yourArray[7]; Also, suppose that in your implementation of C++, variables of type int use... (Sherlock Holmes) This section discusses partially filled arrays and gives a brief introduction to sorting and searching of arrays This section includes no new material about the C++ language, but does include more practice with C++ array parameters s PARTIALLY FILLED ARRAYS Often the exact size needed for an array is not known when a program is written, or the size may vary from one run of the program... different ways We will call them indexed variables, though they are also sometimes called subscripted variables or elements of the array The number in square brackets is called an index or a subscript In C++, indexes are numbered starting with 0, not starting with 1 or any other number except 0 The number of indexed variables in an array is called the declared size of the array, or sometimes simply the... needed to hold three variables of type int to the number for the address of a[0] The result is the address of a[3] This implementation is diagrammed in Display 5.2 Many of the peculiarities of arrays in C++ can only be understood in terms of these details about memory For example, in the next pitfall section, we use these details to explain what happens when your program uses an illegal array index Pitfall... INTRODUCTION An array is used to process a collection of data all of which is of the same type, such as a list of temperatures or a list of names This chapter introduces the basics of defining and using arrays in C++ and presents many of the basic techniques used when designing algorithms and programs that use arrays You may skip this chapter and read Chapter 6 and most of Chapter 7, which cover classes, before... function then outputs a message to the screen telling the index of the last array index used The formal parameter int a[] is an array parameter The square brackets, with no index expression inside, are what C++ uses to indicate an array parameter An array parameter is not quite a call-by-reference parameter, but for most practical purposes it behaves very much like a call-by-reference parameter Let’s go through... arguments can be plugged in for the same array parameter The first of the following calls to fillUp fills the array score with five values, and the second fills the array time with ten values: fillUp(score, 5); fillUp(time, 10); You can use the same function for array arguments of different sizes, because the size is a separate argument s THE const PARAMETER MODIFIER When you use an array argument in a function... 1600 units We therefore round to the nearest thousand Thus, 1600 will be the same as 2000 and will produce two asterisks The array production holds the total production for each of the four plants In C++, array indexes always start with 0 But since the plants are numbered 1 through 4, rather than 0 through 3, we have placed the total production for plant number n in indexed variable production [n-1]... endl; } void scale(int a[], int size) { for (int index = 0; index < size; index++) a[index] = round(a[index]/1000.0); } 68 69 70 71 int round(double number) { return static_cast(floor(number + 0 .5)) ; } 72 73 74 75 76 77 78 79 80 81 82 void graph(const int asteriskCount[], int lastPlantNumber) { cout . 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++, . #define NDEBUG line (or commenting it out). Not all comment assertions can easily be translated into C++ Boolean expressions. Preconditions are more likely to translate easily than postconditions are kind of placeholder that is filled in with a function argu- ment when the function is called. In C++, there are two methods of performing this substitution, call by value and call by reference,