cs1ch8p1.htm
 

 

CHAPTER 8

AN EVEN BETTER CONTRACT PROGRAM


Part 1

  


Table of Contents

1. The Story
of C++!

(The basics for any beginner!)


2. The

of C++

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



3. The Patterns





I. Analyzing the Code Implications of an Improved Program
If Olympia started to use her contract program, her two biggest complaints would be that she could not save the data at the end of the day and that she was stuck with whatever number of contracts were written into the program and, therefore, could not add or delete contracts. We noted at the end of the last chapter that the issue of saving data will be covered in chapter 10 when we talk about files. Now that we have learned about arrays, however, we can tackle the second problem.

The solution requires that we make an array of contracts. In the last chapter we created an array of 10,000 inventory items where each element of the array represented an existing product. We will start the same way here by creating an array of contracts where each element of the array represents an existing contract. Later we will deal with the issue of adding and deleting contracts.

In the inventory program we had a code for each item in the inventory. Our original analysis of Olympia's contract program did not worry about such a code or contract ID since we only had five contracts. However, if we are going to have many contracts and later be adding and deleting them we need to have some way of uniquely identifying each contract.

We can use contract ID's as we used the ID numbers 1 through 5 in the code we completed in chapter 6 in the file ch6cntr2.cpp. There, we used switch statements to determine which contract to pass as a parameter to the 'DisplayInfo' or 'ChangeInfo' functions. A glance at that code, however, will indicate the problems that would arise if we decided that Olympia was to have 20 or a 100 contracts. Our switch statements would get much bigger. The problem is that we have to pass a different variable depending on which contract we wish to handle. Examine the code carefully to see the truth of this.

In the last chapter we saw that it is possible to have access to the individual elements of an array simply by using the appropriate value for the subscript. For simplicity's sake, we used the item code as the 'appropriate value' for the subscript. Note that this was somewhat artificial because in any real environment, item codes are not sequential. The same will also be true for contract ID's, especially when we add the ability to delete contracts. However, for now, we will use contract ID's as subscripts. This will make our code simpler while we focus on other issues.

II. An Array of Contracts and Constructor Issues
Our first step in this improved contract handling program is to work on declaring a new array type and variables of that type. The class name used in chapter 6 for contracts was 'Contract' so one might assume that to declare a new type we could simple write:

    const
      MAX_CONTRACTS = 100;

    typedef Contract ContractArray[MAX_CONTRACTS];

Good assumption! However, things are a bit more complex when we proceed to declare a variable of this type. Consider the line:

ContractArray contracts;

As an array declaration it is perfectly legal. However, consider what it does. It creates an array of 100 instances of the class 'Contract'. But, remember, as we have written the constructor for the class 'Contract' , every time an instance is created, the information on square footage, number of desks, and number of days must be provided. That is not being done in this declaration!

A. Default Values
It turns out that in C++ it is not easy to provide the necessary values for each element of an array of class instances at array declaration time. What we need to do is write a constructor that creates instances with default data. The idea is that if an instance being created is not given specific values for its instance variables then it will use some values likely to be valid or that, at least, make sense as initial values. Notice that this is different from leaving the instance variables filled with garbage. When we use the term 'garbage' for a variable's value we are referring to some value that was left over from the last time the memory associated with this variable was used. A default value is a value we explicitly put into the memory associated with a variable but which is, at best, a guess at the value that will ultimately go there.

For example, if we are dealing with instances of bank accounts where each instance has one property representing the amount of money in the account and a second property representing the interest rate, we might say that the default values are 0 for the amount and 4% for the interest rate - assuming:

  1. that it is better to start an account with no money in it and adjust the amount later rather than the other way around and,
  2. that most accounts in this particular bank have a 4% interest rate.

In the case of the Contract class it makes most sense to set the values for the three instance variables to 0 if not told otherwise.

We could accomplish this by simply changing the constructor for the 'Contract' to class so that it receives no parameters and sets the values of all properties to 0. This would mean, however, that we could not instantiate an instance of the class with specific values as we did before. When creating an individual instance using this new constructor, one would have to write code that first instantiated the instance with default values and then went back in and changed the values one by one using the 'change... functions.

B. Function Overloading
What we want is the ability to instantiate instances both with and without specific property values and C++ allows us to do this. It is legal to write two constructors (or as many as are needed) that have the same name but have different numbers and/or types of parameters. This is called function overloading. In our case then we will have two constructors. They are shown below:

Contract(int sqFootage, int numDesks, int numDays);
(the one we have already seen)

and

Contract();

These constructor functions must have the same name because they are both to act as constructors for the "Contract' class and by definition a constructor for a class has the same name as the class. In general the compiler knows which function to use (among a set of functions all with the same name) by looking at the number and type of actual parameters used when the constructor is called. In our case, since one constructor expects three integer parameters and the other none, if there are three actual parameters, all of which are integers, the first constructor is called; but, if there are no parameters, the second constructor is called. And, of course, the compiler will generate an error if we try to call the constructor any other way.

Be aware that constructor calls are somewhat implicit. The call takes place when the instance is declared. In the case of the array declaration above, 100 instances are declared and therefore 100 calls are made to a constructor for the class 'Contract'. Since each call has no parameters, the constructor with no formal parameters is used. The constructor definition for this second version would look as follows:

    Contract::Contract()
    {
      squareFootage = 0;
      numberOfDesks = 0;
      numberOfDaysPerWeek = 0;
    }

Compare this with the first constructor's definition. The code, of course is slightly different to reflect the different values being assigned the three data members.

You are allowed to overload functions in C++ as long as the there is something different about the parameter lists. The difference can be in terms of the number of parameters in the two functions, in terms of different types of parameters, or in terms of both. Note that one can have different types returned by the two functions but the compiler does not look at this in deciding which function to use. In other words, if the number and type of parameters are the same but the return types are different, the compiler will have no way to determine which one to call at run time. For example, the declarations:

void Function1(int x, double y);
void Function1(double x, int y);

are valid since the first parameter in one declaration is of type 'int' while in the second declaration it is of type 'double'. On the other hand, the declarations:

void Function1(int x, double y);
char Function1(int x, double y);

are not valid because the only difference between them is in the return type.

Constructor overloading is the most common form of function overloading. Later we will look at a second form of overloading involving operators. This is a very powerful addition to C++.

The new 'Contract' class declaration is shown below.

// Declaration of the class Contract
// File: contract.h

class Contract
	{public:
		 Contract(int sqFootage, int numDesks, int numDays);
		/*
		Purpose:	to instantiate (create) an instance of the class 'contract'.
		Goal:		a new instance of class 'contract' now exists

		Inputs: 	NONE
		Outputs:	NONE
		Receives:	Square Footage, number of Desks, number of Days (all 
					Integers)
		Returns:	NONE
		*/

		Contract();
		/*
		Purpose:	to instantiate (create) an instance of the class 'contract' 
							with default values.
		Goal:		a new instance of class 'contract' now exists

		Inputs: 	NONE
		Outputs:	NONE
		Receives:	NONE
		Returns:	NONE
		*/

		void ChangeSquareFootage(int sqFootage);
		/*
		Purpose:	To change the value of the square footage data member
		Goal:		The square footage data member has a new value
		Inputs:		NONE
		Outputs:	NONE
		Receives	The New Square Footage (an integer)
		Returns:	NONE
		*/

		void ChangeNumberOfDesks( int numDesks);
			// Design comments go here.


		void ChangeNumberOfDays( int numDays);
			// Design comments go here.

		int ProvideSquareFootage();
		/*
		Purpose:	To Return the Square Footage of an Office
		Goal:		The Square Footage is returned
		Inputs:		NONE
		Outputs:	NONE
		Receives:	NONE
		Returns	the Square Footage (an integer)
		*/

		int ProvideNumberOfDesks();
			// Design comments go here.

		int ProvideNumberOfDays();
			// Design comments go here.

		double ProvidePerWeekCharge ();
		/*
		Purpose:	To calculate and return the per week charge for an office
		Goal:		The per week charge is returned
		Inputs:		NONE
		Outputs:	NONE
		Receives:	Square Footage, number of Days Per Week, number of Desks 
		(all integers)
		Returns:	The Per Week Charge (a double)
		*/

	private:
		int squareFootage;
		int numberOfDaysPerWeek;
		int numberOfDesks;
};
III. Passing Instances as Array Elements
With this second constructor the original array declaration

ContractArray contracts;

is now valid. Each of the 100 instances held in the array, has the same value of 0 for all three properties. Of course, the program should immediately fill in the correct property values for all 100 instances. As we have already said, ordinarily this would be done by reading the information about old contracts from a file. Since we do not yet know how to do this and since any other approach involves a lot of extra typing, let's change the program to involve only 5 instances. Remember this can be easily done by simply changing the value of the constant, 'MAX_CONTRACTS'. Now we only need input 3 values for each of five instances for a total of 15 values. To save typing as we test our program, we will hard code in the same values we used in the chapter 6 version of this program and not ask the user for the values.

A quick review of the final version of the Contract program in chapter 6 reveals that 'main' was very simple and the real work began in the function ' ProcessUserChoices'. Here the five instances of Contract were instantiated so here is where we should declare the array of instances:

    void ProcessUserChoices()
    	{
    	// Code to create the five instances
    	ContractArray contracts;
    	InitializeInstances(contracts);
    	// Rest of the code goes here
    	}
    
As noted above, the declaration of the variable 'contracts' creates 5 instances of the class "Contract each with the same property values - the default values placed in the various data members by the version of the constructor without parameters. To fix this the last line above calls a function whose purpose is to modify the property values. Let's look at that function's declaration for a moment:

void InitializeInstances(ContractArray contracts);

The function needs one parameter, the array of contracts. It will return this array but as we have already learned, a function cannot return an array using the standard return mechanism. We also learned that in C++ array parameters are automatically set up to allow the parameter to be the return vehicle. In other words, we don't need to do anything to have this function return whatever values are placed into the array.

We will look at the simple code for this function's definition later. Assuming that it works when we get arouind to coding it(- as is standard practice in modularized coding) we can proceed with 'ProcessUserChoices'. After some variable declarations, the older version of the code used a switch statement to handle the user's choices. Note the use of the imbedded switch statement to allow us to call the same function but with the different contracts as actual parameters. Using our array variable we can drastically simplify this code. Here is the code fragment dealing with the 'D' and 'C' choices:

choice = GetOperatorChoice();
while (!done)
{   switch (choice)
    {   case 'D':
        case 'd':
           contractID = GetContractID();
           while (contractID != 0)
           {   if ((contractID > 0) && (contractID <=  MAX_CONTRACTS))
                                                      // in range?
               {   DisplayInfo(contracts[contractID - 1]);
                        // minus 1 because contracts go from 1 to
                        // MAX_CONTRACTS                                                                                          
                        // while array goes from 0 to MAX_CONTRACTS - 1
               }
               contractID = GetContractID();
           }
           break; // case 'd'

        case 'C':
        case 'c':
           contractID =  GetContractID();
           while (contractID != 0)
           {   if ((contractID > 0) && (contractID <= MAX_CONTRACTS))
                                                           // in range?
               {   ChangeInfo(contracts[contractID - 1]);
                        // minus 1 because contracts go from 1 to
                        // MAX_CONTRACTS                                                                                          
                        // while array goes from 0 to MAX_CONTRACTS - 1
               }
               contractID = GetContractID();
           }
           break; // case 'c'
      // Rest of code for the switch statement
      }
   }

In each case, we ask for the user's choice and as long as it is not zero, we enter the loop which allows us to continue Displaying or Changing contracts until we are finished. In place of the imbedded switch statement we place an 'if' statement to make sure the chosen contract ID is in the allowed range. Then we call the 'DisplayInfo' or 'ChangeInfo' procedures using as our actual parameter a specific array element:

DisplayInfo(contracts[contractID - 1]);
or
ChangeInfo(contracts[contractID - 1]);

Remember that the array elements are all instances of the class 'Contract'. Therefore, if we call 'DisplayInfo' or 'ChangeInfo' passing an element of the 'contracts' array, we are passing an instance of 'Contract'. But, why use 'contractID - 1' as the index value? This is because we are prompting the user to enter contract ID's between 1 and 5 (MAX_CONTRACTS) but arrays number their elements from 0 to one less than the max. Thus, if the user enters the value 1 - meaning the first contract - the code should look for that contract in the zero-th spot in the array. Fun, isn't it!

Another example: if the user enters a 3 to display the information on the third contract, the third instance in the array of contracts (element 2 of the array) is passed to the function 'DisplayInfo'. Because 'DisplayInfo' was written to expect to receive an instance of 'Contract' in the original design of this program, it does not need to change at all. In fact, very little of this program changes with the introduction of arrays. This is again an example of the power of both modularized code and the object oriented paradigm.

IV. Calling Function Members With Array Elements
To stress a point one more time: An array element can be used anywhere a variable of the same type as the array element can be used. Since the old version of the code passed variables of type 'Contract' to 'DisplayInfo' and 'ChangeInfo', we can now pass an array element whose type is also 'Contract'.

A. Defining 'InitializeInstances'
The same is also true when calling a member function. The code for "ChangeInfo', for example, used the variable 'contract', which represented an instance of class 'Contract', to call the three member functions that change the properties of an instance of the class:

contract.ChangeSquareFootage(sqFootage);
contract.ChangeNumberOfDesks(numDesks);
contract.ChangeNumberOfDays(numDays);

In the one yet undefined function 'InitializeInstances' for our new version, we need to call these same three member functions to change the values of the newly instantiated instances. Since the instances all exist as array elements, we need to use the names for the array elements in place of 'contract' at the beginning of each call. The first contract has the array element index of 0 so we write:

contracts[0].ChangeSquareFootage(1000);
contracts[0].ChangeNumberOfDesks(3);
contracts[0].ChangeNumberOfDays(5);

to set its values.

Be sure to compare this code with the code just above it. The only difference is that 'contracts[0]' has been substituted for 'contract'. In other words, we are again using an array element in place of a variable name. This is legal since 'contract' and 'contracts[0]' are both of type 'Contracts'.

The complete code for 'InitializeInstances' is therefore:

void InitializeInstances(ContractArray contracts)
{

// In real program this information would be read in from a file.
// In this test code we will hard code in the initial values.

contracts[0].ChangeSquareFootage(1000);
contracts[0].ChangeNumberOfDesks(3);
contracts[0].ChangeNumberOfDays(5);

contracts[1].ChangeSquareFootage(500);
contracts[1].ChangeNumberOfDesks(10);
contracts[1].ChangeNumberOfDays(3);

contracts[2].ChangeSquareFootage(200);
contracts[2].ChangeNumberOfDesks(1);
contracts[2].ChangeNumberOfDays(4);

contracts[3].ChangeSquareFootage(2000);
contracts[3].ChangeNumberOfDesks(20);
contracts[3].ChangeNumberOfDays(5);

contracts[4].ChangeSquareFootage(300);
contracts[4].ChangeNumberOfDesks(2);
contracts[4].ChangeNumberOfDays(2);
}

B. A New Function, 'DisplayAll'
To extend this program a bit we could, for example, add a new option - Display All. This would allow a user to see all the contracts with one key stroke. (At present the user would have to type each contract identifier in, one at a time.). To accomplish this, we would, of course, need to add a new option in 'ProcessUserChoices and a new item to the menu- label if 'L' for 'List All':

    case 'A':
    case 'a':
      DisplayAll(contracts);
      break;

The declaration for 'DisplayAll' would be the same as for 'InitializeInstances':

void DisplayAll (ContractArray contracts);

And, here is the definition:

    void DisplayAll (ContractArray contracts)
    {
    	int sqFootage;
    	int numDesks;
    	int numDays;
    	double charge;
    
    	for (int contract = 0; contract < MAX_CONTRACTS; contract++)
    	{
    		sqFootage = contracts[contract].ProvideSquareFootage();
    		cout << "The square footage for contract " << (contract+1) << " is: "
    			  << sqFootage << endl;
    
    		numDesks = contracts[contract].ProvideNumberOfDesks();
    		cout << "The number of desks for contract " << (contract+1) << " is: "
    			  << numDesks << endl;
    
    		numDays = contracts[contract].ProvideNumberOfDays();
    		cout << "The number of days for contract " << (contract+1) << " is: "
    			  << numDays << endl;
    
    
    		charge = contracts[contract].ProvidePerWeekCharge();
    		cout << "The per week charge for contract " << (contract+1) <<"  is: "
    			  << charge << endl;
    		cout << endl << endl;
    	}
    }
    
This code simply uses a mixture of what we have already learned:
  • the same 'for' loop approach we learned in chapter 7 to handle all the elements of an array;
  • 'contract + 1' to translate from the zero based array counting scheme to the 'ones' based scheme humans use when we output the actual contract number;
  • 'contracts[contract].Provide...' to send a message to a specific instance of the array of instances.

There is a set of parentheses around 'contract+1' to clarify that we want the addition to take place before we output the value of 'contract'. By the way, it would have been incorrect to write 'contract++' in this case because that would have incremented the value of 'contract' itself. If you are puzzled about this statement, TRY IT!

V. The List: An Initial Look at Knowledge Representation
This program is beginning to look useful. The next step is to allow Olympia to add and delete contracts. One way to do this is to have an area of memory set aside with space for contracts and a way to keep track of how much of that space has been used. We have not needed to keep track of this so far because we have immediately filled all the elements of our arrays.

What we need now is a more complex data structure, a structure that not only allows us to store elements as the array does but also includes the new functionality of adding and deleting. Many people call such a structure a list so that is the name we will use. Be aware that what we are about to create here is a specific example of the very general type 'list'. We are bordering on having yet another pattern!

A. A Revised Set of Specifications
First, however, we have changed the problem enough that it is time for a return to specifications. Below is an updated program narrative. You are urged to update the interface analysis developed in chapter 5. Here we will again skip this and focus on discovering the objects and classes. It's again underline the nouns and circle the verbs time:

Olympia owns a small office cleaning business. She wishes to have a program to keep track of the contracts she has with various businesses. Each contract involves one office complex and should keep track of the square footage of the office, the number of desks in the office, and the number of days per week the office is to be cleaned. A user of this program should be able to change any of this information and get all of it plus the per week charge which is calculated based on the formula:

      Weekly Charge = Days per Week * ($0.05 per square feet + $5 per desk)

Users should also be able to add new contracts and delete existing ones. . When adding contracts the contract ID, square footage of the office, the number of desks in the office, and the number of days per week the office is to be cleaned all must be provided. To delete a contract, the user enters the contract ID. No contract can exist that does not have all this information provided initially. Olympia has set a limit on her business of 100 different contracts in order to have time for her family and the other real things of life.

All the changes relevant here are in the second paragraph. First, we can drop the nouns 'family' and 'things of life' since they are really editorial comments. Likewise, the new verb 'provided' has nothing to do with an action of the program. It talks about what the user will do. Don't let such things confuse you.

There are two new verbs that we do need to pay attention to - 'add' and 'delete'. Our earlier analysis discovered one class - contract. Are add and delete operations performed by a contract? If you think carefully, you will realize that nothing is added to or deleted from the contracts themselves . Rather, contracts are added to or delete from something else. What is that 'something else' - what object handles the adding and deleting?

The introduction to this section gave away the answer but it is interesting to note here that the problem narrative only indirectly indicates the need for a new object type, a new class. Something needs to hold all these contracts and allow them to manipulated. That 'something' is a list. Thus, in a bit we will design a new class that we might call 'ListOfContracts'. This class will be special because in this program we will only have one instance of this class.

Whenever you have a problem that involves grouping together a collection of items, consider the possibility of creating a new class one of whose properties is the collection itself. We could actually have created a new class to hold the contracts in the last few chapters. We didn't because the built-in C++ type 'array' met our needs quite well and there was no special functionality to be attached to this array type. As we shall see, a list is more complex than simply an array and does have extra functionality.

Let's start, however, by trying to create the list type using only an array:

    typedef
      Contract ListOfContracts[MAX_CONTRACTS];

    ListOfContracts contracts;

As we have designed the constructor for the class 'Contract' this code will instantiate MAX_CONTRACTS instances of the class. Each of these will have the value of 0 in all its properties. No actual contract can exist with these values so we will use this array of contracts, all with 'zero-ed' property values, to represent a set of contracts waiting to be filled out. We could have rewritten the constructor to have no assignment statements:

    Contract::Contract()
    {
    }

and thus have kept garbage in the values of the instances but why change what we have if it works? And, it is probably better that we know what an empty contract looks like in case we accidentally try and use one.

We start then with zero contracts in the list. How do we keep track of this and update the amount as we add contracts? There has to be some kind of counter that can be incremented when a new contract is added and decremented when a contract is deleted. Here we see that an array by itself will not work. There are at least two aspects to a list - the collection of objects and a counter.

We now have two properties (data members) for our list data structure - the collection and the counter - and two function members - 'add' and 'delete'. Note that the approach just described here for discovering the class(es) needed as well as their responsibilities and properties is somewhat different from what we did in chapter 5. Remember, object oriented analysis is still more of an art than a science so do what works but CHECK YOUR WORK CAREFULLY!!!

Actually, we can and should take advantage of what we learned in chapter 5. To check our work so far, see if there is more to this new class, and formalize our conclusions, we need to create a CRC card for our new class. So far the two responsibilities for the class 'ListOfContracts', in addition to constructing itself, are 'add' and 'delete'. Now, there was a third italicized verb in the second paragraph of the problem narrative, - 'exist' - and, of course, instances do exist. However, beyond stating the obvious, this verb indicates no new functionality or responsibility for the class so our CRC card looks as follows:

Figure 8.1


When doing the CRC card for 'Contract' we did not proceed to discuss collaborators because there was only one class to begin with. Now, however, we have two classes. Do either of these classes use the other as part of its work. Note that the class 'contract' can get along quite well without having any lists - we have written a program that demonstrates this. However, the class 'ListOfContracts' can't really exist without having a 'Contract' class to hold instances of. In other words, 'Contract' is a collaborator of 'ListOfContracts' and we will see in the code for 'ListOfContracts' that the class 'Contract' must be known.


Figure 8.2

With the CRC card in hand, we finish the analysis by checking to see if there are any new properties for our list class. The properties we have discovered so far (the collection of contracts and the counter to hold the number of contracts in the collection) were not found by looking at the underlined nouns in the problem narrative. Of course, they could have been discovered that way if, for example, the narrative had included a sentence such as, "The program will keep track of the number of contracts in the collection of contracts". But, no such sentence was included in the narrative. This points to the need to use every tool at one's disposal - including working as a team -in hopes that someone on the team will notice missing details.

The narrative does have two new nouns - 'limit' and 'contract ID'. The word 'limit' refers to the maximum number of contracts and it could be represented as a property of the class. However, it is already needed in the code as a constant indicating the maximum size of the array. Therefore, it is somewhat redundant. On the other hand, it is possible that later we will represent a list using a mechanism other than an array in which case explicitly representing the maximum would be beneficial. For that reason, let's include it even that it has no immediate use.

The notion of a 'contract ID' clearly is not a property of 'ListOfContracts'. As we noted earlier, it is the Individual contract that has an ID. Technically, we probably should have made this ID a property of the 'Contract' class when we first discovered it but, as long as we were not deleting or adding contracts, it was unnecessary. Deletes change everything. When a user wants to delete a contract, they should not have to know where in the array the specific contract they want to delete is stored. In fact, given the notion of encapsulation, neither the user nor the programmer of the main program even knows that we are using an array to implement the list of contracts. What users should provide is some way of identifying the contract they want deleted - thus the contract ID. This ID will be used to search through the list looking for the contract to be deleted.

VI. Re-Evaluating the Implementation of the User Interface and the Design of 'ProcessUserChoices'
Our design has become more complex. We now have two classes and those two classes interact with each other. In addition, our use of contract ID's means we will have to change the simple way we previously accessed the individual elements of the array of contracts. No longer can the user enter a value that corresponds directly with an a specific location in the array.

At this point it is good practice for the design team to walk through the various processes involved in this program and see if the various member and non-member functions still work together as expected. It is amazing how beginners, who often have trouble visualizing how the various components of a program work together, will avoid this step while experienced programmers, who would seem to have a better grasp of the interactions involved, will take advantage of this.

Let's start with an analysis of the processes involved in simply displaying the information about a contract. After a 'D' has been entered to indicate that the user wants to display the information about a contract, the contract ID is requested. Once this is typed, the function 'ProcessUserChoices', as designed in this chapter, used the value entered by the user as an index into an array of contracts and passed an element of the array of contracts to 'DisplayInfo'. First hint of trouble: the re-designed program does not provide the main program with direct access to any array. (The array is now encapsulated inside the list.) Nor does the new version use contract ID's as indices. How then will the function 'ProcessUserChoices' get a contract to pass to 'DisplayInfo'?

So, we know there is a problem. Before running off to solve it, we should look at more of the program. We might gain some information that will guide us in devising a solution. What happens, then, when the user chooses to change the information about some contract. Again, a contract ID is entered and we run into the same problem. We need a way to get back the contract to be passed to the function that makes the changes. Not only that but there is the added problem that once the contract has been changed it needs to be put back into the list and no mechanism seems to exist to do that. We could have the system delete the old contract and then add the new contract but that seems a bit convoluted.

Moving on, let's look at 'DisplayAll'. When the user chooses to display all the contracts, there is no need for any specific contract ID. But, we still have a problem - how does the function 'DisplayAll' get access to the contracts in the list! Remember, the array of contracts is encapsulated and, therefore, is unavailable to functions that are not members of 'ListOfContracts'.

The design for the processes to delete and add contracts seem to be the only parts that are OK . In the case of deleting, the user will enter the contract ID and this will be passed to the member function 'Delete' which will do all the work. To add a contract the user will enter all the information necessary, a contract instance will be created, and finally, the member function 'Add' will be called with the newly instantiated contract being passed as a parameter.

It makes sense that 'Add' and "Delete' work since we have yet to commit to much by writing code for them and because they were planned as part of the new class, 'ListOfContracts'. The rest of the functions are leftovers from a program that existed before we worried about adding and deleting or about using a list. Take a moment to think about what you might do to fix these functions before proceeding to the next section .