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.

 

 

CMPT 225 Home

 

John Edgar (johnwill@sfu.ca)