Preconditions and Postconditions(先决条件和后置条件)
When you are using a function, you only need to think about what the function does. You need not think about how the function does its work.
For example, suppose you are writing the temperature conversion program and you are told that a function is available for you to use, as described here:
// convert a Celsius temperature c to Fahrenheit degrees
double celsius_to_fahrenheit (double c);
Your program might have a
double
variable called
celsius
that contains(包含) a Celsius temperature. Knowing this description, you can confidently write the following statement to convert the temperature to Fahrenheit degrees, storing the result in a double variable called fahrenheit:
fahrenheit = celsius_to_fahrenheit (celsius);
Procedural abstraction(过程抽象)
When we pretend(假装) that we do not know how a function is implemented, we are using a form of information hiding called procedural abstraction.
To make procedural abstraction work for us, we need some techniques for documenting(文档) what a function does without indicating(表明) how the function works.
We could just write a short comment(注释) as we did for celsius_to _fahrenheit. However, the short comment is a bit incomplete----for instance, the comment doesn't indicate(表明) what happens if the parameter c is smaller than the lowest Celsius temperature.
For better completeness and consistency(完整性和一致性), we will follow a fixed format that always has two pieces of information called the
precondition and the postcondition
of the function, described here:
Preconditions and Postconditions |
A precondition is a statement giving the condition that is required to be true when a function is called. The function is not guaranteed to perform as it should unless the precondition is true. |
A postcondition is a statement describing what will be true when a function call is completed. If the function is correct and the precondition was true when the function was called. then the function will complete, and the postcondition will be true when the function call is completed. |
For example, a precondition/postcondition for the celsius_to_fahrenheit function is shown here:
double celsius_to_fahrenheit (double c);
// Precondition: c is a Celsius temperature// e no less than absolute zero.
// postcondition: The return value is the temperature c converted to Fahrenheit degrees.
The important of Precondition and postconditions
Precondition and postconditions are more than a way to summarize a function's actions. Stating these conditions should be the first step in designing any function.
Before you start to think about algorithms and C++ code for a function, you should write out the function's
prototype, which consists of the function's return type, name, and parameter list, all followed by a semicolon(分号).
As you are writing the prototype, you should also write the precondition and postcondition as comments(注释).If you later discover that your specification(说明书) cannot be realized in a reasonable way, you may need to back up and rethink what the function should do.
Precondition and postconditions are even more important when a group of programmers work together.
The Temperature Conversion Program
// File: temperature.cxx
// This conversion program illustrates some implementation techniques.
#include <cassert> // provides assert function
#include <cstdlib> // provides exit_success
#include <iomanip> // provides setw function for setting output width
#include <iostream> // provides cout
using namespace std; // allows all standard library items to be used
double celsius_to_fahrenheit (double c)
// precondition: c is a Celsius temperature no less than absolute zero.
// postcondition: The return value is the temperature c converted to fahrenheit degrees.
{
const double MINIMUM_CELSIUS = -273.15;
assert (c >= MINIMUM_CELSIUS);
return (9.0 / 5.0) * c + 32;
}
void setup_cout_fractions (int fraction_digits)
// precondition: fraction_digits is not negative.
// postcondition: all double or float numbers printed to cout will now be rounded to the spe// cified digits on the right of the decimal point.
{
assert (fraction_digits > 0);
cout.precision (fraction_digits);
cout.setf (ios::fixed, ios::floatfield);
if (fraction_digits == 0)
cout.unsetf (ios::showpoint);
else
cout.setf (ios::showpoint);
}
int main()
{
const char HEADING1[] = " Celsius";
const char HEADING2[] = "Fahrenheit";
const char LABEL1 = 'C';
const char LABEL2 = 'F';
const double TABLE_BEGIN = -50.0;
const double TABLE_END = 50.0;
const double TABLE_STEP = 10.0;
const int WIDTH = 9;
const int DIGITS = 1;
double value1;
double value2;
// set up the output for fractions and print the table headings.
cout << "CONVERSIONS from " << TABLE_BEGIN << " to " << TABLE_END << endl;
cout << HEADING1 << " " << HEADING2 << endl;
// each iteration of the loop prints one line of the table
for (value1 = TABLE_BEGIN; value1 <= TABLE_END; value1 += TABLE_STEP)
{
value2 = celsius_to_fahrenheit (value1);
cout << setw(WIDTH) << value1 << LABEL1 << " " ;
cout << setw(WIDTH) << value2 << LABEL2 << endl;
}
return EXIT_SUCCESS;
}