Previous Section Main Menu Next Section

CHAPTER 10

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

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

VII. Defining the New Contract Class
The changes we will examine here are all due to the addition of the string properties. In addition they are somewhat repetitious because we perform the same basic set of operations over and over on the different strings. For that reason, not all of the changes will be explicitly discussed here. The complete code is under the file name "contrct6.cpp". (Note that this file includes the file 'string.h' to have access to the two string manipulations functions (strlen and strcpy) used here.)

A. The Constructors
We begin with a look at the code for the first constructor:


Contract::Contract(int ID, int sqFootage, int numDesks, int numDays,
			char* name, char* oStreetAddr, char* oCity,
			char* oState, char* oZip)
{  	contractID = ID;
	squareFootage = sqFootage;
	numberOfDesks = numDesks;
	numberOfDaysPerWeek = numDays;

	int len = strlen(name);
	contracteeName = new char[len + 1];
	strcpy(contracteeName, name);

	len = strlen(oStreetAddr);
	officeStreetAddress = new char[len + 1];
	strcpy(officeStreetAddress,oStreetAddr);

	len = strlen(oCity);
	officeCity = new char[len + 1];
	strcpy(officeCity,oCity);

	len = strlen(oState);
	officeState = new char[len + 1];
	strcpy(officeState,oState);

	len = strlen(oZip);
	officeZip = new char[len + 1];
	strcpy(officeZip,oZip);
}
Note that the parameter list does not include the default values. They are only included in the declarations. The code to assign the string parameters to the various string data members follows a consistent format. The length of the string parameter is found; enough memory for a string of that size (plus 1 for the null character) is requested, and its address assigned to the corresponding data member. Finally 'strcpy' is used to copy one string to the other.

The second constructor is the same with all the strings automatically made to be empty.


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

	contracteeName = new char[1];
	strcpy(contracteeName, "");

	officeStreetAddress = new char[1];
	strcpy(officeStreetAddress,"");

	officeCity = new char[1];
	strcpy(officeCity,"");

	officeState = new char[1];
	strcpy(officeState,"");

	officeZip = new char[1];
	strcpy(officeZip,"");
}
Since all the strings are empty, the are represented by one element arrays - just enough room for the null character.

Now let's take a look at the code for the copy constructor.


Contract :: Contract(const Contract& c)
{	int len = strlen(c.contracteeName);
	contracteeName = new char[len + 1];
	strcpy(contracteeName, c.contracteeName);

	len = strlen(c.officeStreetAddress);
	officeStreetAddress = new char[len + 1];
	strcpy(officeStreetAddress,c.officeStreetAddress);

	len = strlen(c.officeCity);
	officeCity = new char[len + 1];
	strcpy(officeCity,c.officeCity);

	len = strlen(c.officeState);
	officeState = new char[len + 1];
	strcpy(officeState,c.officeState);

	len = strlen(c.officeZip);
	officeZip = new char[len + 1];
	strcpy(officeZip,c.officeZip);

	contractID = c.contractID;
	squareFootage = c. squareFootage;
	numberOfDaysPerWeek = c.numberOfDaysPerWeek;
	numberOfDesks = c.numberOfDesks;
}

Remember, the purpose of this is to copy the string properties. The other properties are dealt with via straight assignment statements as is shown in the last four lines of this function. To copy the strings we write essentially the same code we saw in the first constructor. Consider the code to copy the contractee name. First, the code gets the length of the name to be copied:

int len = strlen(c.contracteeName);

Note that since this constructor is a member function of 'Contract', it has access to the data members of any instance of 'Contract', including 'c'. Also, note that since 'c' is not the instance that was sent the message but, instead, was passed as a parameter, we must use the syntax 'c.contracteeName'. In other words, the code is referring explicitly to the name field of the instance 'c'. If we dropped the 'c' we would be referring to the instance that was sent the message - the one that will receive the copied data.

We have seen this dot notation used before in function calls but not with data members. Up to now, we have not needed to access the data members of one instance of a class while working with a different instance of the same class. Instead, the code that needed access to the data members of an instance was not part of any member function and, therefore, had to use the public member functions of the class in question. Since data members usually are declared in the private part of a class declaration, they are unknown outside the class and cannot be directly accessed by code using the class. To repeat: it is legal to use the dot notation with a data member of the 'Contract' class here because this function is a member of the 'Contract' class and thus has access to the data members of all instances of the class.

Once we have the length, we request enough memory for that many characters plus 1 and assign the address to 'contracteeName'. This time we do not place the 'c.' in front of the data member name because we are referring to the new instance being created not to the instance from which we are getting the data for this new instance.

Finally, we make the copy using 'strcpy'. Note that here we use both 'contracteeName' by itself and with the 'c.'. In other words, we are copying the contents of 'c.contracteeName' to the 'contracteeName data member of the new instance.

You will see that all the other string properties are handled the same way. Not only that, but the code for the 'CopyContract' member function is the same. It may seem strange that we need the same code in multiple places. The reason is that these functions have different purposes: one is a constructor, the other is used to copy from one existing instance to another. Any smart coder will not type this code twice. Instead he or she will use the copy and paste features of the editor extensively. When this code was written, one of the authors first wrote the first constructor. Then he copied the code to the copy constructor and added the dot notation. He was then finished with the copy constructor. Next, he copied this code to the 'CopyContract' function and had three 'complex' functions finished in no time.

B. The Destructor
We now move to the destructor. There are five arrays being pointed to by data members of the class so we need five delete operations:


Contract :: ~Contract()
{	delete [] contracteeName;
	delete [] officeStreetAddress;
	delete [] officeCity;
	delete [] officeState;
	delete [] officeZip;
}
Remember that the [] is needed because each of these data members points to an array.

C. The Rest of the Function Members

The 'Provide...' and 'Change...' member functions are all similar to each other except for the parameter and data member names used. We will examine 'ProvideOfficeCity' and 'ChangeOfficeCity' here:


char* Contract:: ProvideOfficeCity()
{	return officeCity;
}

void  Contract:: ChangeOfficeCity(char* city)
{	delete [] officeCity;  			// delete the whole string array
	int len = strlen(city);
	officeCity = new char[len + 1]; 	// don't forget the null char
	strcpy(officeCity, city);
}
As with all 'Provide...' functions this one simply returns the contents of the appropriate data member, 'officeCity'.

'ChangeOfficeCity' is a bit more complex. We are changing the string contents of the 'officeCity' field and we don't know how much memory will be required for the new string. The easiest way to handle this is to return the memory used by the old string and then request just the amount of memory required for the new string. To return the memory, the first line of the function is

delete [] officeCity;

The rest of the code is exactly what we have done with every other string assignment. In fact, this code was also copied from elsewhere and modified to fit the variable names used here.

There is quite a bit of code to this modified version of the definitions for 'Contract'. As noted, however, much of it is quite repetitive and easily copyable. The trick in code like this is to understand what needs to be done and then figure out how to do it as easily as possible using the capabilities of your editor. Again, for the complete code, check out contrct6.cpp

Top of Section Main Menu Next Section