cs1ch10sec4.htm
 CHAPTER 10

ANOTHER VISIT WITH THE CONTRACT PROGRAM
OR
WORKING WITH DYNAMICALLY SIZED LISTS


Section IV : Re-Evaluating the Contract Program Design Section I: An Expandable List of Contracts Section II: Declaring the New ListofContracts Section III: Defining the New ListOfContracts
Section V: Adding String Properties to the Contract Class Section VI: Declaring the New Contract Class Section VII: Defining the New Contract Class Section VIII: Modifying the Main Program

  


Table of Contents

Learning C++:
An Index of Entry Points


2. The

of C++

A reference document on the basic elements of C++.



3. The Patterns



Index!



A. Designing an Iterator
Now imagine that the programmer working on the main program says that she is uncomfortable with the fact that she is in charge of some of the output and you as programmer for 'ListOfContracts' are in charge of the rest. Remember that in chapter 8 we discussed this issue and decided to compromise and have the main program handle the displaying of individual contracts but have 'ListOfContracts' handle the 'DisplayAll' function. Code-wise this works well in the sense that 'DisplayAll' was easy to write inside 'ListOfContracts'. However, every time the programmer for 'Contracts' adds a new property, all three programmers have to make changes to their code. That is not a good sign.

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 end of the Public part of the class
    	....
    	void Reset();
    
    	Contract GetNext();
    
    	bool AreThereMore();
    
    private:
    	int numContracts;       // indicates next available slot in list
    	int presentMax;         // present size of array
    
    	int next; 	  	// Used to iterate through the list
    			        // Holds the 'next' unaccessed contract in a set of requests
    	....
    	// The rest of the private part
    };
    
    
What is not shown here is that the member function 'DisplayAll' has been deleted. In its place are

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
To be different, let's skip for the moment the discussion of how these new functions will be defined and move to a discussion of the main program. We do this to emphasize that once everyone has agreed on the interface (in this case, once everyone agrees on the names, parameters and return types of the three new public functions), work can proceed on both 'ListOfContracts' and the main program in parallel.

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

    case 'L':
    case 'l'::
      contracts.DisplayAll();
    break;

This, of course, calls the now non-existent member function that used to display all the contracts. In its place we include the code:

    
    case 'L':
    case 'l':
    	contracts.Reset();
    	for (; contracts.AreThereMore()  ; )
    	{  contract = contracts.GetNext();
    		DisplayInfo(contract);
    	}  
    	break;
    
The first line for this 'case' resets the list of contracts so that the iterator will start with the first contract in the list. That is simple enough but look at the 'for' statement! It looks as if the programmer forgot a few things. Actually, this is another example of versatility of this statement.

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

contracts.Reset();

To indicate that there are no initializations, we simply include a semi-colon right inside the parenthesis.

After that parenthesis there is the call:

contracts.AreThereMore()

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:

    for (int j = 0; ;i++ )
    {
      cout << j << endl;
    }

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:

    for (; ;)
    {
      // some code
    }

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
It is now time to examine the code for the three new member functions.:


	void  ListOfContracts :: Reset()
	{ next = 0;
	}

	Contract  ListOfContracts :: GetNext()
	{
		return listOfContracts[next++];
	}

	bool  ListOfContracts :: AreThereMore()
	{	if (next < numContracts)
		{	return true;
		}
		else
		{	return false;
		}
		// More complex: the single line: return (next < numContracts)
	}
'Reset' simply gives 'next' the value 0, the index of the first array element. 'GetNext' returns the contract in the array element indexed by 'next'.

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:

cout << ++var1;

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

    index = 0;
    while (index < 10)
    {
      // some code
      index++;
    }

it really does not make a difference whether we write:

index++; or ++index;

In neither case is the incremented value being used right away.

The same discussion is relevant to the "--" operator. The code

cout << index--;

would cause the value in 'index' to be output before the value is decremented. But,

cout << --index;

will cause the value to be decremented before it is output.

*******************

Returning to the case of:

return listOfContracts[next++];

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:

    Contract c1;
    c1 = listOfContracts[next++];
    return c1;

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:

if (next < numContracts)

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:

return (next < numContracts)

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++"

The 'for' Statement
Returning Memory to the Heap

Top of Section Main Menu Next Section