|
Table of Contents
Learning C++:
An Index of Entry Points
2. The A reference document on the basic elements of C++.
3. The Patterns
|
We have already noted the changes to the data members of the
'ListOfContracts' class - we will use the variable name 'presentMax' in
place of 'limit' and 'listOfContracts' will be a pointer to an array
instead of an array itself. This last change means we no longer need a
user defined data type for the array. Nor, do we need the constant
indicating the number of elements in the array. However, we decided to use
a constant to indicate by how much the array should grow each time it gets
full. Of the three functions we designed algorithms for in the previous
sections, two of them, the constructor and 'Add', already exist in the
class declarations. True, we will need to modify their code but the class
declarations concern themselves only with what not how. Therefore, since there are no changes
in the receives and returns for these functions, no changes need be made
in their declarations. We do need to declare the third function - the one
that will increase the size of the array. Note that this is another one of
those functions that only instances of the class need. Like the already
existing search function, users of this class will not directly call this
new function and therefore, like 'Search', it should be declared in the
private part of the class. Here is the code: Before we review the key points of this code, note the
additional comments. It is not enough to include the "Purpose, Goal,
Receive and Return" information. In fact, the code examples are already
starting to drop this in hope that you are coming to understand the need
to do this analysis on your own. What is still needed, now even more than
ever, are comments that explain key or complex parts of the code. Thus the
code includes descriptions of key variables, constants and lines of code
as well as algorithms for complex functions. The code itself follows the discussion we just had. To review:
The function 'IncreaseSize is declared in the private section. Note
that it has no parameters and returns nothing. One might question this
because certainly 'IncreaseSize' needs the array of contracts if it is
going to change its size. However, 'IncreaseSize' is part of the class.
It, therefore, has direct access to the data members of the instances of
the class, including 'lisOfContracts'- the data member that points to the
array. Anytime the function member 'Add' is called, it will be associated with
a specific instance of the class 'ListOfContracts. If 'Add' then calls
'IncreaseSize', 'IncreaseSize' will have access to the data members of the
same instance, including 'listOfContracts'. Since it has access to these
data members, it does not need to have them passed as parameters.
There is one new piece to this class declaration that we have not
yet discussed. We know that all classes have at least one constructor.
They also have a destructor - a function that gets rid of
(destroys) instances when they are no longer needed. What this means is
that the memory used for the data members of the instance is returned to
the system. Destructor functions are often not explicitly called in
programs. Instead, they are called implicitly by the program when an
instance goes out of existence. For example, when we have declared a class
instance as a local variable of a function, that instance is destroyed
when the function returns. - just as all other local variables are
destroyed. All this takes place automatically. As with constructors, if we do not declare a destructor, the system
declares one for us. As long as we do not want anything special to happen
when an instance is destroyed, the default destructor is just fine. This
is usually the case when the data members of the class do not include
pointers. That is why we have not had to worry about destructors up to now
- our classes did not use pointers. However, there is a problem when one or more of the data members is a
pointer. The default destructor returns the memory used by the pointer
itself but NOT the memory pointed to by the pointer. Consider an instance
of 'ListOfContracts'. Here is a picture of the memory involved in such an
instance.
![]() Figure 10.5 If the destructor for this instance is called, the memory used by
'numContracts', presentMax, and the pointer 'listOfContracts' would be
returned to the system. However, the destructor knows nothing about the
array being pointed to by 'listOfContracts' so its memory would not be
returned. Here is how memory would look in such a situation. Note that the
array is out there but there is no way to access it. This is an example of
a memory leak.
To get this memory returned, we need to explicitly declare and
define a destructor that will use a built-in operator that is the opposite
of 'new' - the delete operator. This operator takes a pointer and
returns to the system whatever memory is being pointed to. For example, if
we have the code:
memory would look as follows:
If the program later has the line:
memory will look as follows:
Note that the memory for the variable 'ptr' still exists but not the
memory it pointed to - the memory that used to hold the value 5. Note
further that although the memory no longer exists (actually it is on the
heap available to be used by another request), the memory location 'ptr'
still acts as if it is pointing to it. Thus, if 'ptr' is used incorrectly,
there could be problems. Deleting the memory for an array is only slightly more complex. Consider this modified version of the code we just saw:
Although the code says ptr points to an integer, we know that 'ptr'
actually points to an array of integers. It is relatively easy for the
system to keep track of this fact and thus return all the memory
allocated. As long as we are dealing with an array of integers, doubles,
chars, bool, or some simple user defined type, there is no problem.
However, there is a problem when we have an array of some class type and
that class type has a non-default destructor. Now, that destructor needs
to be called separately for each element of the array. For example, suppose Olympia wants a separate list of contracts for
each year she has been in business. We could implement this with an array
of type 'ListOfContracts'. Further, suppose that we declare this array as
a local variable in some function in our program. When that function
finishes, the array represented by the local variable is destroyed and, in
the process, the destructor for 'ListOfContracts' must be called for each
element of the array. At different stages in its development, C++ has had different ways of
handling this. At first special code - indicating how many elements there
were in the array - was only required when the array held instances of a
class for which a specific destructor had been defined. Other
methodologies were proposed, and you would not believe the amount of
argument that surrounds details such as this. In any case, the latest
approach and the one used in the latest compilers says that any time a
pointer points to an array, the programmer should use 'delete' followed by
a empty pair of brackets, followed by the pointer. This tells the system
that there is an array of something to be deleted and it handles
determining if a destructor needs to be called and, if so, how often. Thus to delete the memory accessed by 'ptr' above we would write:
Back to destructors: Since 'ListOfContracts' includes a pointer to an
array of contracts, we need a destructor to delete the array. To declare a
destructor for a class, one simply puts a tilde (~) in front of the class
name. Like constructors, destructors cannot return anything and the
declaration code does not even include the word 'void'. Also, destructors
cannot receive anything so they have no parameters. The 'Contract' class,
as presently designed, does not need an explicitly declared destructor but
if we wanted one, we would declare it as:
Notice that what distinguishes a classes destructor from a constructor
with no parameters is the tilde. To declare the destructor for
ListOfContracts, we follow the same procedure and write:
Topics Covered in the "Essentials of C++" |