Department of Engineering

IT Services

11. Advanced topics

department image The Glue (Graphics Library for Undergraduate Education) graphics package provides C++ functions for doing simple graphics and plotting data.

Enumerated constants

There are many examples of data which is not inherently numeric. For example, the days of the week, months of the year, colours. We can refer to such data types by defining symbolic constants and using these symbolic constants in expressions in the program. For example:

   const int Mon=0, Tue=1, Wed=2, Thu=3, Fri=4, Sat=5, Sun=6;

C++ provides a more convenient way for the user to define a new data type. The C++ enumeration statement:

   enum Days {Mon, Tue, Wed, Thu, Fri, Sat, Sun};

creates a new variable type with legal values Mon, Tue, Wed, Thu, Fri, Sat, Sun which are in fact symbolic constants for 0,1,2,3,4,5 and 6. The enumeration is simply assigning an integer to a symbolic constant. The definition makes it convenient to work with days of the week.

Variables can be declared as having the user-defined type and this will ensure that they are only assigned one of the legal values. The following statement declares the variable day to have the user-defined type, Days.

   Days   day;

Character arrays

A common use of the one-dimensional array structure is to create character strings. A character string is an array of type char, which is terminated by the null terminator character, '\0'. The symbol \0 looks like two characters but represents one. It is called an escape sequence.

A character array can be initialised on declaration by enclosing the characters in double quotes. The null character will be automatically appended. In the following example the subject[] array has the text Information Engineering assigned to it, along with the null character. Its size is set to 24 (includes space and null characters) by the compiler. The array surname assigned by the cin << surname statement can only be assigned one word of text. The simple input statement stops reading characters when the first whitespace character is encountered.

// CharacterArray.cc
// Initialisation of a character array and passing to functions

#include <iostream>
using namespace std;

void PrintExtensionNumber(char phoneNumber[]);

int main()
{
   char surname[50];
   char phone[11];
   char subject[] = "Information Engineering";

   // Get user details
   cout <<  "Enter surname and telephone number: " << endl;
   cin  >>  surname >> phone;

   cout <<  surname << " is a student of " << subject << endl;

   // If first two digits are 3 then it is a university number.
   if( phone[0]=='3' && phone[1]=='3') 
   {
      cout <<  "Please contact on university extension ";
      PrintExtensionNumber(phone);  
   }
   else 
   {
      cout <<  "Please contact on external number 9-" << phone[0];
      PrintExtensionNumber(phone);
   }
      
   return 0;
}

// Function to print out extension number. Ignores first digit.
void PrintExtensionNumber(char phoneNumber[])
{
   int i;
   
   for(i=1; phoneNumber[i] != '\0'; i++)
   {
     cout << phoneNumber[i];
   }
   cout << endl;
}

Multi-dimensional arrays

The arrays that we have looked at so far are all one-dimensional arrays, however, C++ allows multidimensional arrays. For example to declare a two-dimensional array to represent the data of a 3 by 4 matrix called myMatrix we could use the following statement and syntax:

   float  myMatrix[3][4];

You may think of the element with indices i and j, myMatrix[i][j], as the matrix element in the i row and j column, but remember that array indices always start from 0.

The following program illustrates the passing of arrays to and from functions. The function ComputeMatrix() assigns values to the elements of a 2 by 2 rotation matrix. The actual parameters passed are the name of the rotation matrix (i.e. memory address of the first element) and an expression to determine the rotation angle in radians. The element matrix[0][1] is the element of the first row and second column of the matrix.

The function RotateCoordinates() computes the coordinates of a point after transformation by the following equation:

It is passed the name of the matrix and the name of the initial position vector and transformed position vector.

// RotationMatrix.cc
// Program to calculate coordinates after rotation

#include <iostream>
#include <cmath>
using namespace std;

void ComputeMatrix(float matrix[2][2], float angle);
void RotateCoordinates(float rot[2][2], float old[2], float transformed[2]);

int main()
{
   float angle, point[2], transformedPoint[2];
   float rotation[2][2];
           
   // Get angle of rotation and initial position from input.
   cout << "Enter magnitude of rotation about z-axis in degrees: " ;
   cin >> angle;
   cout <<  "Input x and y coordinates: " << endl;
   cin >> point[0] >> point[1];

   // Calculate coefficients of rotation matrix and transform point.
   // The value of pi is declared in math as M_PI.
   ComputeMatrix(rotation, (M_PI*angle/180.0));
   RotateCoordinates(rotation, point, transformedPoint);

   // Output result.
   cout << "The (x,y) coordinates in the rotated system are ";
   cout << transformedPoint[0] << " and " << transformedPoint[1] << endl;
   return 0;
}

void ComputeMatrix(float matrix[2][2], float angle)
{
    matrix[0][0] = cos(angle);
    matrix[0][1] = sin(angle);
    matrix[1][0] = -sin(angle);
    matrix[1][1] = cos(angle);
}

void RotateCoordinates(float rot[2][2], float old[2], float transformed[2])
{
    transformed[0] = (rot[0][0] * old[0]) + (rot[0][1] * old[1]);
    transformed[1] = (rot[1][0] * old[0]) + (rot[1][1] * old[1]);
}

Structures

Arrays are examples of data structures in which all the elements must be of the same type. C++ allows the user to define more general data structures, using the keyword struct to define a collection of related variables of any type, called a structure. For example:

struct StudentType{
   char  name[100];
   int   age;
   int   entryYear;
   float marks[5];
   char  college[20];
};

defines a new data type called StudentType, which is made up of five fields or data members: two integers, an array of floating point numbers and two character arrays. The body of the structure definition is delineated by braces and must end with a semicolon. The definition is placed at the top of a program file, between include directives and the function prototypes.

Once a structure has been defined, the structure name can be used to declare objects of that type. This is analogous to declaring simple variables.

   StudentType person;
   StudentType firstYear[400];

declares the variable person and the one-dimensional array, firstYear[400] to be of type StudentType.

Data members of a structure are accessed and assigned values by specifying the field (data member) name using the dot operator, for example:

   person.age = 19;
   firstYear[205].entryYear = 1999;

Structures have the advantage that, by collecting related items together, they can be manipulated as single items. For example whole structures can be copied using an assignment statement (unlike arrays):

   firstYear[24] = person;

and manipulated efficiently with repetition control statements:

   for(i=0; i< 400; i++)
   {
      firstYear[i].entryYear = 1999;
   }

An introduction to object-oriented programming and classes

One of the most important differences between the C++ programming language and other programming languages is the emphasis on the representation of data using programmer or user-defined data types. In C++ an extension to the definition of structures allows the user to include both data members (as above) and member functions which are allowed to process the data. The encapsulation of data and functions into packages called objects of user-defined types called classes is a key part of object-oriented programming.

In its simplest form, a class is like a structure which includes the definition of functions (member functions or class methods) which are allowed to process the data. See simple example below.

Classes and Objects

The class (e.g. Date in the example) can be considered as a specification while the actual item (e.g. today) is an instance of a class and is called an object. Declaring an object is very similar to declaring a variable:

   class-name object-name;

Accessing data members and functions

The data members and member functions of the class can be accessed by simply naming them in conjunction with the name of the object they belong to using the dot operator.

   object-name . item-name

Defining a class member function

The declaration and definition of class member functions is similar to those used for standard functions: we use function prototypes to declare the functions and place the statements to be executed in a function definition. The only difference is that with a class member function we must tell the compiler which class the function is a member of. This is done by including the name of the class in the function header using a scope resolution operator represented by ::.

   return-type class-name :: function-name( parameter-list )

Restricting access to class members

One of three levels of access can be specified for each class member (both data and functions) using the keywords public, private or protected followed by a colon. These refer to how the class members may be accessed in a program.

The public members of a class may be accessed directly from anywhere in the program which has access to an object of the class. The private members can only be read or modified by class member functions.

A simple example

We consider a simple example which shows how to create a simple class and define the class's member functions.

// SimpleClass.cc 
// A program to demonstrate creation and use of a simple class for dates
#include <iostream>
using namespace std;

// Declaration of Date class
class Date {
  public:
  void set(int, int, int);
  void print();

  private:
  int year;
  int month;
  int day;
};

int main()
{
   // Create a Date object called today
   Date today;

   // Call Date member function set()
   today.set(1,9,1999);
   cout << "This program was written on ";
   today.print();
   cout << endl; 
   return 0;
}

// Date member function definitions
void Date::set(int d, int m, int y)
{
  if(d>0 && d<31) day = d;
  if(m>0 && m<13) month = m;
  if(y>0) year =y;
}

void Date::print()
{
  cout << day << "-" << month << "-" << year << endl;
}

Reading and writing to Files

Storage of data in variables and arrays is temporary. Files are used for permanent retention of large amounts of data. We will now show how C++ programs can process data from files. To perform file processing in C++ the header file <fstream> must be included. The latter includes the definitions of ifstream and ofstream classes (special structure definitions). These are used for input from a file and output to a file.

The following command opens the file called, name.dat, and reads in data which it stores sequentially in variables, a, and b

The object called fin is declared to be of type (class) ifstream. The member function called open() is used to associate the file name, name.dat, with the object name, fin.

   ifstream fin;
   fin.open("name.dat");
   fin >> a >> b;

In a similar way we can write data (in this example, the values of an array) to a file called output.dat with:

   ofstream fout;
   fout.open("output.dat");
   for(i=0; i<N; i++)
   {
      fout << array[i]  << endl;
   }

Note that fin and fout are arbitrary names assigned by the programmer. (They are known as ifstream and ofstream objects respectively.) Using fin and fout highlights the similarity with the simple input and output statements of section 5 which use the input and output stream objects cin and cout respectively. The syntax of the input and output statements is identical. The only difference is that care must be taken to ensure the files are opened and closed correctly, i.e. that the file exists and is readable or writable. This can be checked by testing the value of fin.good() or fout.good(). These will have the values true if the files are opened correctly.

The following fragment of a program reports an error if the file name specified was not found or could not be opened and prompts the user for another file name.

// OpenFile.cc
// Program to read data from a file. File name is input by user.

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
   char fileName[80];

   // Get filename from keyboard input
   cout << "Enter input file name: ";
   cin >> fileName;

   // Declare fin to be of type (class) ifstream
   // Associate file name with fin
   ifstream fin;
   fin.open(fileName);

   // Prompt for new file name if not able to open
   while(fin.good() == false)
   {
      cout << "Unable to open file. Enter a new name: ";
      cin >> fileName;
      fin.open(fileName);
   }
   return 0;
}

After finishing reading from and writing to files they must be closed with the statements:

   fin.close();
   fout.close();

and the ifstream and ofstream objects fin and fout can be re-assigned to other file names.

Back to top