CMPT
225 Lab - A Dynamic Array
In
this lab, you are going to create a C++ dynamic array class that inserts values
and sums those values. This lab will guide you through the process of creating
the class. The first parts of the implementation will be given to you.
A
dynamic array is an array that grows as necessary. In practice, this entails
creating a new array when the old array is full and copying the existing values
into that new array.
Writing a
C++ Class
.h and .cpp
Files
C++ classes are made up of a
header file and an implementation file. Both files should have the same
name except that the header file has a .h
extension while the implementation has a .cpp extension. The header file contains the class
interface, and the .cpp file contains the
implementation. The header file consists of the class name, and the name (and
type) of the member variables and the header for each of the methods. The
.cpp file consists of the definition for each of the
class methods.
Public
or Private?
Class member variables and methods
should be specified as being either private or public.
Private variables or methods can only be accessed from within the class,
whereas public variables and methods can be accessed from outside the
class. There are a couple of good general design principles to follow
when deciding whether or not to make a method or variable public:
Only make
something public if it needs to be public; note that not all methods need to be
public, many classes have private helper methods that never have to be accessed
directly from outside the class.
Make all member variables
private, if necessary, write public getter and setter methods for the
variables. This allows you to write the setter methods to ensure that any
class invariants are maintained (e.g. such as ensuring that an array size is a
positive number). There are exceptions to this principle, but you won't
encounter any in this example.
Constructors
and Destructors
Every class requires at least one
constructor that creates new objects of that class. A class will often
have multiple constructors that build new objects in slightly different
ways. A constructor is a method that has exactly the same name as the class and has no
return type; it is responsible for setting the initial values of the member
variables of an object.
C++ classes also require destructors. A
destructor is responsible for de-allocating any dynamic memory that an object
uses. If you don't write a destructor for a class a default one is
created for you. This class will allocate dynamic memory for the array so
will require a destructor.
Class
Description
The class creates an array in dynamic memory
which increases in size as necessary.
The class will have the following public methods
default
constructor - allocates space in dynamic
memory for an integer array of size 2
destructor - deallocates dynamic memory associated with
the array
insert(int) - sets the value of the next free element of
the array to the parameter
sum() - returns the sum of the values in the array
size() - returns the number of values currently
stored in the array
The class should also have the following private attributes
a pointer
to an int (that will refer to the
array)
an integer
that records the actual size of the array
an integer that records the number of
values stored in the array
Header
File
The header (ArrayClass.h) file should contain
the class definition, which should be
separated into public and private sections. Here is the entire class definition.
#pragma once
class ArrayClass
{
public:
// Constructors and Destructors
// Default constructor
// POST: Creates an ArrayClass object with an array of size 2
// PARAM:
ArrayClass();
// Destructor
// POST: De-allocates dynamic
memory associated with object
~ArrayClass();
// Accessors (getters) and
mutators (setters)
// Sets the value of the next
free element
// PRE:
// POST: Sets index n to value,
doubles size of arr if n == arrSize,
increments n
// PARAM: value = value to be
set
void insert(int value);
// Returns the sum of the
values stored in the array
// PRE:
// POST: Returns sum of the
first n elements of arr
int sum();
// Returns the number of
elements stored in the array
// PRE:
// POST: Returns n
int size();
private:
int* arr;
int arrSize;
int n;
};
The header should also include any files whose
contents are referenced in the header (none in this case).
Notes
PRE stands for pre-condition -
something that must be true for the method to function correctly; POST
stands for post-condition - the state of the program after the method has run;
PARAM stands for parameter
All the methods are public because they might be used
(called) by modules or functions outside the class, for example a function
might want to know the size or sum of an ArrayClass object
All the attributes are private so that their values
can be protected from inappropriate changes by non-class functions, for example
changing the currentSize
of the array without actually adding a new value to
the array
Starting
the Implementation File
The implementation file (ArrayClass.cpp) should contain the
definitions (i.e. implementations) of each of the class methods. The connection
between the class definition in the .h file and the method definition in the .cpp file is
the result of two things - neither of which are that the files were both created
by an IDE or that they have the same name!
The .cpp file should include the header file
and each method should be given its fully qualified name, which includes the
name of the class. Both of these are illustrated below.
Constructor, Destructor and
Size Methods
Here is the first part of the .cpp file which contains the default constructor and the
destructor
#include "ArrayClass.h"
// Default constructor
// POST: Creates an ArrayClass object with an array of size 2
// PARAM:
ArrayClass::ArrayClass()
{
arrSize = 2;
arr = new int[arrSize];
n = 0;
}
// Destructor
// POST: De-allocates dynamic
memory associated with object
ArrayClass::~ArrayClass()
{
delete[] arr;;
}
// Returns the number of
elements stored in the array
// PRE: Creates an ArrayClass object with an array of size 2
// POST: Retruns
n
int ArrayClass::size()
{
return n;
}
Notes
A constructor initializes the attributes of an
object, for this class this entails setting the size of the array, creating the
array in dynamic memory and setting the number of elements currently stored in
the array to zero.
The variables arrSize and n are attributes of an ArrayClass object, and are not variables declared in the constructor;
changing the first line to int
arrSize = 2 would mean
that arrSize
was a local variable belonging to the constructor and the object's arrSize attribute
would remain un-initialized - which would be problematic
Constructors have the same name as the name of the class
and unlike other methods (and functions) do not have a return type.
Each method must be preceded by the name of the
class and the scope resolution operator (::). This
informs the compile that the function definitions are the implementations of
the ArrayClass methods.
The destructor is responsible for de-allocating
any dynamic memory that has been allocated for an object. The name of the
destructor is always the name of the class preceded by a tilde (~), like
constructors, destructors do not have return types. Destructors should never
(or at least very rarely) be called explicitly. They are invoked either
explicitly by a call to delete or
automatically when an object's lifetime has expired.
The delete
command deletes any dynamic memory associated with a pointer; in this case it
must be followed by []s since arr points to an array.
Implementing
Insert
The insert method should set the value of the
next free element to its parameter and increase the size of the array as
necessary. The steps of this method are set out below in comments.
// Sets the value of the next
free element
// PRE:
// POST: Sets index n to value,
doubles size of arr if n == arrSize,
increments n
// PARAM: value = value to be
set
void ArrayClass::insert(int value)
{
// Check to see if array is
full - if(
// Double arrSize
// Assign arr
to temp
// Asign
new array of arrSize to arr
// Copy values from temp
// Deallocate memory assigned
to temp
// end if
// Insert new value at index n
and increment n
}
Complete the method.
Testing
Insert
Copy and paste the code shown
below into a second .cpp file (i.e. this should be a
separate file from your ArrayClass .cpp). This
is a brief test of the class constructor and insert method. In practice, each
method should be rigorously tested as it is implemented before moving on to the
next. This is particularly important when one method relies on another. For
example, I would suggest never starting to implement a method that removes items from a data structure
before you are absolutely certain that your insertion
method works perfectly.
#include <iostream>
// for cout
#include "ArrayClass.h"
using namespace std;
// Function Prototype
void arrayClassTest();
// Main function that is called
when the program is executed
int main(){
arrayClassTest();
return 0;
}
void arrayClassTest(){
ArrayClass ac;
ac.insert(1);
ac.insert(2);
cout << "ac.size()
= "<< ac.size()
<< endl;
// Insert the values 1 to 7 in
ac1
for(int
i=3; i <= 40; ++i){
ac.insert(i);
}
cout << "ac.size()
= "<< ac.size()
<< endl;
}
Implement
Sum
Given time, implement and test the sum method.
What's
Missing?
Whenever you write a class that allocates
dynamic memory you should implement the troika of a destructor (we did this), a
copy constructor and an overloaded assignment operator. We will discuss the
latter two at a later date.
John Edgar (johnwill@sfu.ca)