CHAPTER 10
|
Table of Contents
Learning C++:
An Index of Entry Points
2. The A reference document on the basic elements of C++.
3. The Patterns
|
A. Designing an Iterator Some would argue that 'Contract' itself should handle any contract
output. Then, only one programmer (the one in charge of 'Contracts' )
would be required to make changes in the output functions when a contract
property was added (or deleted). However, imagine that a number of
different programs were going to use the Contract class - one to prepare
reports, one for billing, one for taxes, one for advertising etc. Each of
these would probably require its own output format, and there is no way
that the programmer for the Contract class could conceive of all the ways
the data might be used. For that reason many argue that a class like 'Contract' should only
provide a way to access the individual data members (the 'Provide'
functions in our version) and leave how that data is used (output,
calculated with, etc.) to the code for specific programs. That is the
approach we will take here. Let's rewrite the main program and
'ListOfContracts' so that the main program handles 'DisplayAll'. Remember, what makes implementing 'DisplayAll' difficult is that the
main program has no direct access to the individual contracts. It cannot
on its own go inside the list of contracts to access them one by one for
display purposes. One way to handle this is to include in
'ListOfContracts' the capability to iterate through the list.
Iteration in this context is the process of asking for the 'next'
contract, displaying it, and stopping when there are not more contracts.
What does 'ListOfContracts' need to handle this? First, there must be
some indicator of what the 'next' contracts is. This will be an index into
the array. It should start at 0 (the first contract in the array) and
increase each time a contract is accessed. There also must be a function
that returns the next contract. In addition, there must be a function that
allows a user program to ask if there are still more contracts to get.
Finally, since the user of the program may want to display all the
contracts more than once, there needs to be a function that resets the
indicator of the next contract back to 0. Below is the code for the part of the 'ListOfContracts' declaration
that shows these additions: the three new member functions, which are all public since they will be
used in the main program. The data member 'next' is another one of those
variables that is only used inside the class. Therefore, there are no
public functions such as 'ProvideNext' or 'ChangeNext' which would allow
user programs to directly change the value of 'next'. Of course, 'Reset'
and 'GetNext' will change the value of this property but user programs do
not have any reason to know how these changes are being made. B. Using the Iterator The changes to the main program are quite simple and they all occur in
the function 'ProcessUserChoices'. To handle the "Display All" choice, the
previous version of this function, had the lines
This, of course, calls the now non-existent member function that used
to display all the contracts. In its place we include the code:
We know that there are three parts inside the parentheses of a 'for'
statement. The first part handles any initializations, the second part
handles end of loop testing, and the third part handles any required
incrementing or other changing of values of the variables used in the
loop. As the code is written, there is no need for any initialization
because that was done by
To indicate that there are no initializations, we simply include a
semi-colon right inside the parenthesis. After that parenthesis there is the call:
We know that 'AreThereMore' will return true or
false so it works well as the test condition. The loop will continue as
long as there are more contracts to get. Note that there is no semicolon
at the end of the line of code we just read although there is one just
after this same code in the for loop itself. The semicolon in the 'for'
loop is NOT part of the call. It is the sign to the compiler that there
are no more test conditions. In chapter 8 we discussed how the 'for' loop can be coded to have
more than one test condition. In the code we are discussing now there is
only one test and there is nothing after the second semi-colon. Normally,
this is where we would put any increments. The fact that there is nothing
here indicates that there are no increments - at least none we need put
here. To see why this is so, we need to examine what goes on inside the loop.
Part of the discussion about the interface of 'listOfContracts' must
include a discussion of what will be expected of each public function -
not 'how' each function will work but 'what' each function will do. In the
case of 'GetNext', it needs to be decided if it will automatically handle
somehow adjusting the instance to indicate the next contract, or if a
special function needs to be called to do this. Some designs call for such
a special function, with a name such as 'Continue' or 'Shift'. In our
case, the fact that there is no addition member function in
'ListOfContracts' means that 'GetNext' must do the work. It will not only
return the 'next' Contract, it will also adjust the data member 'next' to
"point to" the contract after the one in the array just returned. Since
this function does the work of adjusting 'next', there is no need for any
incrementing or adjusting inside the 'for' statement parentheses. Any part of a 'for' statement can be excluded. Here is an interesting
version:
This is an infinite loop! It has no test conditions and therefore has
no way to stop! If you have the time (and a good book to read while you
wait) you might want to make a guess as to what this outputs and then run
it to see if you are right). One can even right:
if you want an infinite loop to perform some activity unrelated to loop
conditions. This may seem very strange but some operating systems might
have a variation of this. Any program that can only be stopped by turning
off the system or somehow shutting it down from outside itself, might have
a loop like this. Back to our discussion on the implementation of the for loop that
displays all the contracts: The loop will continue until all the contracts
have been displayed. Inside the loop, the system will retrieve the next
contract from the list and pass it on to the already existing function
'DisplayInfo. Thus, we take advantage of code that was already written.
Note also, that this iterator could be used for other purposes. For
example, a program that wanted to create bills for all the contracts could
also retrieve the contracts one by one, but instead of sending each one to
a display function, it could send them to a bill writing function. This completes the changes to the main program. Note that this time,
because we are changing the interface between the class and its users, we
need to make changes on both sides. C. Defining the Iterator Functions The use of "++" here is a bit special. Up to
now we have emphasized that "++" increments by 1 the value stored in a
variable. This is true but one can actually put the "++" before or after
the variable and the meanings of these are different. The code cout
<< var1++ would cause a system to output the value in 'var1' and then increment
that value by 1. In other words, if 'var1' had the value 3 before this
line was executed, a 3 would be output and the value would change to 4.
On the other hand, if the code was:
the value would be incremented first and then output. So, if 'var1'
started with the value 3, that value would be incremented to 4 and 4 would
then be output. To summarize: a "++" before a variable means to increment
the value in the variable and then, if something is to be done, do it; a
"++' after a variable means to do anything that is to be done with the
value in the variable and then increment it. When the '++' is before the
variable, we are using the prefix operator, and when the '++' is
afrer the variable, we are using the postfix operator.
Note that when we have the variable with the "++" by itself as in
it really does not make a difference whether we write:
In neither case is the incremented value being used right away. The same discussion is relevant to the "--" operator. The code
would cause the value in 'index' to be output before the value is
decremented. But,
will cause the value to be decremented before it is output.
Returning to the case of:
the system will retrieve the contract in the array element indicated by
the value in 'next' before it is incremented; 'next' will then be
incremented; and finally, the retrieved contract is returned. The 'return'
makes it a bit difficult to see what is happening so consider the
following code which will have exactly the same effect:
Here, the variable 'c1' will hold the contract in the array element
indicated by 'next' before it is incremented. The variable 'next is then
incremented and, finally, the return of the contract 'c1' occurs. In this
way, next is always pointing to the contract to be retrieved next after
'GetNext' finishes'. Note that this function could get into trouble if the
user of this program does not check if there is still another contract to
retrieve (using the function 'AreThereMore'), before it calls 'GetNext'
each time. Sooner or later 'next' will "point" past the end of the array
and strange data will be returned. In programming terms, the results are
unpredictable. The final function, 'AreThereMore', simply asks if 'next' has gone
through all the contracts:
and returns true or false depending on the answer. Note the comment at
the end of the function indicating a more complex way of writing the
code:
This says to directly return the result of the comparison. The code
"next < numContracts" will return 0 if it is not true and some value
other than 0 if it is true. The word 'return' will then cause this value
to be returned to the calling function. Feel free to use this variation of
the code if you feel comfortable with it but both approaches are the same.
It is presented here so that you will have some idea of what is going on
if you encounter this form as you read other code - which you are, of
course, doing at every opportunity you have - if you really want to learn
to code! That completes the discussion of iterators. To see this code run, you
can use the same version of class 'Contract' (contrct4.h and contrct4.cpp. Here are the complete versions of
the modified code for 'ListOfContracts' (ch10lst5.h and
ch10lst5.cpp) and the main program (ch10tst7.cpp) Topics Covered in the "Essentials of C++" |