| |
Main Menu | Next Section |
A. Passing Instances as Array Elements
With this second constructor, the original array declaration
typedef Contract ContractArray[MAX_CONTRACTS];
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'. In that function the five instances of Contract were instantiated, so we will declare the array of instances in the same function:
void ProcessUserChoices()
{
// Code to create the five instances
ContractArray contracts;
InitializeInstances(contracts);
// Rest of the code goes here
}
Let's look at the function's declaration
for a moment:
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:
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 contract ID's 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 contract ID's 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
}
}
or
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:
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:
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)
{
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':
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;
}
}
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
| |
Main Menu | Next Section |