Previous Section Main Menu Next Section

CHAPTER 8

AN EVEN BETTER CONTRACT PROGRAM


Section II:Instances as Array Elements Section I: Analyzing the Code Implications of an Improved Contract Program Section III: The List: A Look at Data Representation Section IV: Lists: Working with Encapsulation
Section V: Class Declarations for Contract and ListOfContracts Section VI: Member Functions for ListOfContracts Section VII: Improving ListOfContracts Section VIII: Rewriting the Non-member Functions

A. Passing Instances as Array Elements
With this second constructor, the original array declaration

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'. In that function the five instances of Contract were instantiated, so we will declare the array of instances in the same function:

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 replace those default values with the values used in the program, the line, "InitializeInstances(contracts);", calls a function whose purpose is to modify the property values. This same function can be used to fill in the appropriate values in any number of ways. Although we agreed above to simply use hard coded assignment statements at this point, we could have this function read the data from a file or get its input from a sophisticated graphical user interface (GUI).

Let's look at the 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 around 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 in this code 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:

In each case, we ask for the user's choice and as long as it is not zero, we enter a loop which allows us to continue Displaying or Changing contracts until we are finished. In place of the embedded 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.

B. 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'.

1. 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 'InitializeInstances', the one yet undefined function 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 simple variable name. This is legal since 'contract' and 'contracts[0]' are both of type 'Contract'.

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);
}

You will find that this code is exactly the same as our very first attempt to use contracts back in Chapter Five, Section VI. B , except for the use of array elements.

2. 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 need to add a new option in 'ProcessUserChoices and a new item to the menu- label it 'L' for 'List All':

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

void DisplayAll (ContractArray contracts);

And, here is the definition:

This code simply uses a mixture of what we have already learned:

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! The code for this program is in the files common.h, contract.h, contract.cpp , and ch8tst3.cpp

Top of Section Main Menu Next Section