Our exercise is to learn how to design and write a program. Since doing so is creating software, this endeavor is sometimes called software engineering. The particular design technique we will be using in this manual is called object-centered design (OCD), a methodology explicitly designed to help novice programmers get started writing software.
The process of developing a program to solve a problem involves several stages:
Do not worry or panic if a topic is confusing and it's not explained in great detail. We will go through each of these topics in subsequent labs.
Yogi Berra once supposedly said,
If you don't know where you're going, you'll end up somewhere else!
This idea is especially important when writing software: you need to know where you are going before you sit down to write a C++ program. This is done by spending some time designing your program.
Helpful hint: A good design makes a program easy to write.
If you are not a novice programmer, spending the time to design a program may seem like a waste, especially at the beginning when problems are relatively easy. However, the problems will soon become more difficult. If you get in the habit of carefully designing your software now (while doing so is easy), then designing elegant solutions for more difficult problems will also be relatively easy. But if you take a short cut now and skip the design stage, you will not master object-centered design, and when the problems get more difficult, you will find that your peers are writing better programs and writing them faster than you.
So be disciplined and get into the habit of carefully designing your software. The remainder of this section will teach you how.
Object-centered design consists of four sub-stages: describing how the program must behave to solve the problem, identifying its objects, identifying its operations, and organizing those objects and operations into an algorithm.
We can describe our program's behavior as follows:
Our program should first display on the screen a greeting, after which it should display a prompt for the lengths of the legs of a right triangle. It should then read these two values from the keyboard. Once it has the two leg lengths, it should compute the hypotenuse length. It should then display the hypotenuse length (and appropriate labels) on the screen.
This behavioral description gives us all of the information we need to get started designing our program. In particular, it provides us with the objects and the operations our program requires to solve the problem. It does not magically fall from the sky, but it's a natural explanation of what we want the program to do. What are the steps you would do to solve the problem? We then throw in steps to read in data and to display the results of the solution.
Once we have our behavior description, we can pick out our objects and operations. True to its name, OCD says we pick out our objects first...
Picking out our objects is as simple as picking out the nouns in our behavioral description (ignoring nouns like "program" and "user"). The result is a list of the objects our program needs to define:
Description | Type | Kind | Name |
---|---|---|---|
the screen | ostream | varying | cout |
a greeting | string | constant | -- |
a prompt for the legs | string | constant | -- |
the length of the first leg | double | varying | leg1 |
the length of the second leg | double | varying | leg2 |
the keyboard | istream | varying | cin |
the hypotenuse value | double | varying | hypotenuse |
labels for the hypotenuse | string | constant | -- |
Once we know the objects in our problem, it is useful to specify the basic flow of information in our program in terms of the objects going in and data going out. For example, we can write:
Specification:input (keyboard):leg1
andleg2
, twodouble
values.
output (screen):hypotenuse
, adouble
value.
Such a specification succinctly states what the program does to solve the problem in terms of its inputs and outputs. (Output items like a greeting, prompts and labels are assumed.) It is good programming style to provide such a specification as part of the program's opening comment, for documentation purposes.
Just as our nouns are objects, verbs are our operations for our algorithm:
Description | Predefined? | Name | Library |
---|---|---|---|
display the greeting | yes | << | iostream |
display a prompt | yes | << | iostream |
read the length of the first leg | yes | >> | iostream |
read the length of the second leg | yes | >> | iostream |
compute the hypotenuse length | ?? | ?? | ?? |
display the hypotenuse | yes | << | iostream |
display the label | yes | << | iostream |
In addition to listing the basic operations, we also list whether or not the operation is predefined; if so, how it is specified, and where the operation is defined.
This table provides us with the basic operations needed to solve our problem; however, there is no predefined operation to compute the length of the hypotenuse of a right triangle. To do so, we must refine this operation by breaking it down into smaller ones. In particular, the Pythagorean Theorem tells us that we need these operations to compute the hypotenuse length:
Description | Predefined? | Name | Library |
---|---|---|---|
compute the square of a leg | yes | pow() | cmath |
add two squared legs | yes | + | built-in |
compute the square root | yes | sqrt() | cmath |
store a value in a variable | yes | = | built-in |
Once we have identified all of the objects and operations needed to solve our problem, we can organize them into a sequence of steps that solves our problem---an algorithm. An algorithm should specify what a program does in fair detail, but it need not worry about the syntax details of a particular language like C++.
We've already noted above some C++ objects that we'll use
(specifically cin
and cout
) and some C++ operations
(e.g., >>
and <<
). We'll cheat a bit in our
algorithm by using these C++ names, but if we wanted to switch
languages, we could easily switch these names.
cout
a greeting for the user.cout
prompts for the two leg lengths.cin
for leg1
and leg2
.hypotenuse
= sqrt(pow(leg1
, 2.0) + pow(leg2
, 2.0))
cout
the value of hypotenuse
along
with an appropriate label.This algorithm provides the blueprint for our C++ program. Once we have it, we are done designing our program, and are ready to begin implementing our design.
Before working through the rest of this lab, make sure you have work through the operating-system and compiler specific portions of Lab #0 to become familiar with your environment.
In the lab1
directory, open up the hypot.cpp
file. If you obtained this from a zipped file, you should
find the file in the lab1
directory; otherwise, you'll
have to create the directory and download the file.
We are going to take a big jump here and simply look at the code for
this program; in most labs, you'll write a lot of this code. Take a
look at the hypot.cpp
file that's provided for you.
You'll play around with the syntax of this program below, but for now compare how the program statements match up with the algorithm steps. For each step of the algorithm, there's usually one and occasionally two C++ statements for the algorithm step. This indicates you have a good algorithm; if you find yourself needing more statements for an algorithm step, then you probably have to revise your algorithm.
After the program is written, we compile the program. Go ahead and do this. (You will not know how to do this unless you've read the appropriate OS and compiler directions from Lab #0.)
In practice, it is best to compile the program on a regular basis, as you write it, so that compiler errors don't overwhelm you at the end of the coding. It will make finding the errors easier. But since this program was given to you, you can move abnormally fast through this step.
The third stage of program development is a thorough testing. The basic idea is to execute the program using sample data values that test the program, to see if it contains any logic errors.
You compiled the program in the previous section, so execute the program with the following values, to see if you get the correct results.
predicted | observed | ||
---|---|---|---|
leg1 |
leg2 |
hypotenuse |
hypotenuse |
1.0 | 1.0 | 1.414214 | |
3.0 | 4.0 | 5.0 | |
5.0 | 12.0 | 13.0 |
Question #1.1: Write down the observed values that you get testing these inputs on the program you compiled.
Unlike programs that are written by students, real world programs may be used for many years. It is often the case that such programs must be modified several times over the course of their lifetimes, a task which is called program maintenance. Maintenance is thus the final (and usually the longest) stage of program development. Some studies have shown that the cost of maintaining a program can account for as much as 80% of its total cost! One of the goals of object-oriented programming is to try to reduce this maintenance cost, by writing code that is reusable.
Question #1.2: What changes might you like to make to this program? (You won't have to implement them, so let the sky be your limit!)
Load hypot.cpp
into your editor.
First of all, you will be making changes to the program, so you should add a modification comment in the comment at the top of the file. Add something like this:
* Modification history: * by John VanDoe in September 2002 for CPSC 185 at Calvin College * Modified to run the experiments for Lab #1.
This should go right after the author information. Recompile and execute the program. It shouldn't execute any differently. That's because that text at the beginning of the document are all comments. But you might wonder what makes a comment.
A comment is text that's useful for the programmer. The compiler will ignore it completely. So if you type junk into a comment, the compiler will ignore it. If you type junk outside of a comment, the compiler will take it as program code and will get confused.
For each of the following questions, make the change suggested and recompile your program. If it compiles okay, we'll assume it runs okay; your answer for the question can be "compiles fine". But if a change generates a compiler error, your answer for the question should be the first error message that the compiler gives you. Always undo your change before going on to the next question.
Question #1.3: What happens when you remove the asterisks (i.e., *
)
before the lines you just added?
Undo your change.
Question #1.4: What happens when you remove the /*
at the very
beginning of the file?
Undo your change.
Question #1.5: What happens when you remove just the /
at the very
beginning of the file?
Undo your change.
Question #1.6: What happens when you remove just the first*
(right after the/
at the beginning of the file?
Undo your change.
You should have a good idea where this comment starts.
Question #1.7: Where do you suppose this opening comment ends?
Another way to introduce a comment is with //
, two slashes.
This type of comment is used to indicate the algorithm steps in the
program.
Question #1.8: Remove one of the //
s in the program. What happens
when you compile the code?
And, yet again, make sure your program is restored back to a compilable state.
You'll find two lines that use the #include
directive right
after the opening comment. These lines tell the compiler that it
needs to access some library files. They're necessary for some of
the operations that the program does.
Question #1.9: What happens when you delete one of the #include
lines?
Question #1.10: What happens when you add some spaces before a #include
?
Question #1.11: What happens when you move one of the includes to the end of the file?
Remember to restore your file after each question.
int main()
The main program is designated by main()
. The main algorithm
must be encoded in this function.
Question #1.12: What happens when you drop the parentheses:main()
becomes justmain
?
Question #1.13: What happens when you drop theint
beforemain()
?
Question #1.14: What happens when you replace the curly braces (i.e.,{
and}
) with parentheses (i.e.,(
and)
)?
Question #1.15: What happens when you add extra spaces before the int
?
Again, restore your program after each question so that it compiles and executes correctly.
The input and output statements for Steps 1, 2, 3, and 5 all begin
with either cin
or cout
followed by objects that
should be displayed and used to read in values. The objects are
separated with the operators <<
and >>
.
Question #1.16: What happens when you replace acout
withcin
?
Question #1.17: What happens when you remove a >>
?
Question #1.18: What happens when you remove a <<
?
Question #1.19: What happens when you replace a>>
with<<
?
Question #1.20: What happens when you replace a<<
with>>
?
And yet again, restore your program after each question so that it compiles and executes correctly.
Before we can use a variable in a C++ program, we must first declare
it. The leg1
and leg2
variables are declared with
this line:
double leg1, leg2;
Question #1.21: What happens when you delete this line?
Question #1.22: What happens when you move it after Step 4?
Question #1.23: What happens when you move it before main()
?
By this point, you've probably run across a change or two that didn't matter. You made the change, the program still compiled, and the program still executed correctly. However, not all of these changes are good. You'll see again and again that there's often many ways to write your program, many of them bad ways.
Helpful hint: Pay careful attention to the way code is written in the examples that you see in this lab manual. Try to mimic this as closely as you can even if something else works just as well.
Be sure to return your file to this original state.
Semicolons end almost every C++ statement.
Question #1.24: What happens when you remove a semicolon from one of the statements?
Question #1.25: What happens when you add an extra semicolon?
Question #1.26: What happens when you add some extra spaces before a semicolon?
You might be a bit worried about the #include
directive; it
doesn't have a semicolon!
Question #1.27: What happens when you add a semicolon after an #include
directive on the same line?
Question #1.28: How do statements and directives differ with respect to semicolons?
Turn in your answers to the questions in this lab exercise.