Author: cs daixie

Exception Handling

Exercise 1: Bounds Checking Array
In the array class we created previously, the bounds checking was very basic. There was no error generated, but setting an element was ignored or the first element was returned. Obviously you want to know if there was an out of bounds error. This is possible by exception handling. Change the Array class to throw exceptions:
•In the GetElement(), SetElement() and index operator throw -1 if the index was toosmall or too big.
•In the main program, create an Array object and access an element that does not exist.Run the program. What happens?
•The exception must be caught, so place the code inside a try … catch block thatcatches an int.
•In the catch handler, print an error message.

Exercise 2: Exception Objects
Throwing an int is an easy solution. But exception handling is also object oriented and allows us to throw an object. In this exercise we will create an exception hierarchy with an ArrayException base class and an OutOfBoundsExceptionderived class as shown in Figure 3:
•You can implement both exception classes in the header file for simplicity.
•Give the ArrayException an abstract GetMessage() function that returns a std::string.
•Give the OutOfBoundsException class a constructor with an int as argument thatindicates the erroneous array index and store it in a data member.
•Override the GetMessage() function and let the implementation return a messagestring saying the given index is out of bounds.
•In the Array class, throw now a OutOfBoundsException object instead of an integer.
•Change the main program so that it catches the ArrayException base class and usesthe GetMessage() function to display an error message.

Polymorphism

Exercise 1: Polymorphic ToString() Function
The ToString() functions of Point and Line override the ToString() from the Shape base class. We saw that we could put aPoint in a Shape* variable. But when calling the ToString() method on the Shape* variable, the function in Shape was called instead the one in Point. To make the compiler generate the required code to find out what type of object the Shape*variable is actually pointing to so it can call the right version; we need to declare the function as virtual. Thus declare the ToString() function in the Shape class as virtual and test the program again. Is the ToString() function of Point called when you use a Shape* that contains a Point now?

Exercise 2: Calling Base Class Functionality
The ToString() function of the Shape class is overridden in the derived classes. But for the derived class it is still possible to use the base class functionality. In the ToString() function of Point and Line we also want to incorporate the ID from theShape base class.
•In the ToString() method of Point, call the ToString() method of the Shape base class:std::string s=Shape::ToString();
•Append the shape description string to the point description string before returning.
•Do this also for the ToString() function in the Line class (and Circle class).
•Test the application again. Is now the ID printed when printing a point or line?

Exercise 3: Virtual Destructors
When objects are removed from memory, the destructor is called. When a derived class destructor is called, it will automatically call the base class destructor. But when you have pointers to a base class, deleting objects might not be done correctly. If not done already, print some text in the destructors of the Shape, Point and Line classes. Then test the following code:
Shape* shapes[3];
shapes[0]=new Shape;
shapes[1]=new Point;
shapes[2]=new Line;
for (int i=0; i!=3; i++) delete shapes[i];
Will the proper destructors (including the destructor of the Shape base class) be called? In this case, the derived class destructor will only be called when the destructor is declared virtual in the base class. Do this in the Shape class and run the code again. Are the proper destructors called now?

Exercise 4: Abstract Functions
Sometimes functions in the base class are only there to be overridden in the derived class. Assume that you want to draw all the shapes using the following code:
Shape* shapes[10];
shapes[0]=new Line;
shapes[1]=new Point;

shapes[9]=new Line(Point(1.0, 2.5), Point(3.4, 5.2));
for (int i=0; i!=10; i++) shapes[i]->Draw();
for (int i=0; i!=10; i++) delete shapes[i];
Create the Draw() function in the Shape base class and override it in the derived classes (point, line and if present the circle class). Simulate drawing by just printing some text. What implementation did you give the Draw() function in Shape? Shape is just an abstraction to work with various kinds of shapes like lines and circles. Shapes don’t have a physical appearance. Therefore its Draw() function will have an empty implementation. But better is to give it no implementation at all by making it a pure virtual member function:
virtual void Draw()=0;
Do this in your code. Try to create an instance of the Shape class. Is this possible? Now the Shape class is really an abstraction. You don’t make shape instances but you can still create shape pointers that point to concrete shapes like point and line. The Shape class is now an abstract base class.

Exercise 5: Template Method Pattern
In this exercise we are going to create a Print() function that is printing the shape information to the cout object. ThePrint() function can use the ToString() to obtain the string to print. You see that the implementation of Print() is in each derived class largely the same; calling ToString() and sending the result to cout. Since the ToString() function is polymorphic, we can use the polymorphic behavior in the Print() function of Shape. Thus:
•Add a Print() function to the Shape class.
•In this function, call the ToString() function and send the result to the cout object.
•In the test program, create a point and line object and call the Print() function. Does itprint the right information even when point and line do not have the Print() function?
You have now created a function for the base class (Print()) that does all the functionality common to all derived classes. Only the part of that function that is different for each derived class is delegated to a polymorphic function (ToString()). This mechanism is an often used design pattern called the “Template Method Pattern”.

Simple Inheritance

Exercise 1: Colon Syntax
The colon syntax can improve the performance of constructors. To test this, make sure that you print some text in the point’s constructors, destructor and also the assignment operator. Now, execute the following code in the test program and count the number of point constructor, destructor and assignment calls:
Line l;
Now, change the constructors in the Line class to use the colon syntax to set the start- and end-point data members and run the test program again. Is the number of point constructor, destructor and assignment calls less than before? Apply the colon syntax also for the Point class constructors and if applicable also for the Circle class.

 

Exercise 2: Creating Shape Base Class
It can be useful to create a hierarchy of related classes using base- and derived classes.
•Classes are related (same family)
•Common data and functionality can be put in a base class.
•You can work with derived classes as if it is the base class.
In this exercise we are going to transform the Point and Line class into a Shape hierarchy as shown in Figure 1.

First create a Shape base class.
•Add a source- and header file for a Shape class.
•Add a data member for an id number of type int.
•Add a default constructor that initializes the id using a random number. You can usethe rand() function from the “stdlib.h” header file.
•Add a copy constructor that copies the id member.
•Add an assignment operator that copies the id member.
•Add a ToString() function that returns the id as string e.g. “ID: 123”.
•Add an ID() function the retrieve the id of the shape.
Next the Point and Line classes (and the Circle class if applicable) must derive from Shape.
•Add the Shape class in the inheritance list of the Point, Line and optionallythe Circle class.
•The constructors of the Point, Line and optionally the Circle class should call theappropriate constructor in the Shapebase class.
•The assignment operator should call the assignment operator of the Shape baseclass. Otherwise the shape data will not be copied.
•Finally add code to the main program to test inheritance:

Improving your Classes

Exercise 1: Extra Constructors

In this exercise we are going to add extra constructors. But first we do a little experiment.

In the Point class constructor and destructor, add some code that displays some text.

In the main program, make sure you use the Distance() function to calculate the distance

between two points. Run the program and count how many times the constructor and

destructor are called. Are they the same?

Now add a copy constructor to the Point class that also displays some text. Also add a

constructor that accepts x- and y-coordinates so you can create a point with the right values

without using the set functions. Use this constructor to create the point from the user input.

Run the program again and count the number of times the constructors and destructor are

called. Is the copy constructor called and is the number of constructor calls now the same as

the number of destructor calls?

We can derive two things from these results:

  1. When calling the Distance() function, the input point is copied (call by value).
  2. You will get the copy constructor ‘for free’ when you do not create one yourself.

Exercise 2: Pass by Reference

In the previous exercise, you saw that the point passed to the Distance() method was copied.

Since creating a copy is unnecessary in this case, change this function so that it passes the

input point “by reference” so that no copy is made. Pass it as “const reference” to make it

impossible to change the input point from within the Distance() function.

Run the program again. It should call the copy constructor fewer times than before.

Also test if you can change the input point in the Distance() function. This should result in a

compiler error.

Exercise 3: Function Overloading

Previously you saw that there could be more than one constructor as long as the input

arguments are different. You can do the same for normal member functions. Thus you can

rename the DistanceOrigin() function to Distance(). Also you can rename

the SetX() andGetX() functions to just X(). The same is true for the setter and getter of the y

coordinate.

Exercise 4: Const Functions

In the test program create a const point and try to set the x-coordinate:

const Point cp(1.5, 3.9);

cp.X(0.3);

Compile the program. Did you get a compiler error? It should give a compiler error because

you try to change a const object.Now replace the line that changes the x-coordinate to code that reads the x-coordinate:

cout<<cp.X()<<endl;

Compile the program again. You will see that is still gives a compiler error even while

retrieving the x-coordinate does not change the point object. This is because the compiler

does not know that the function does not change anything. So we need to mark the x

coordinate getter as const by making it a const function. Do this also for the y-coordinate

getter and the Distance() and ToString() functions because these don’t change the point

object as well.

Recompile the application. It should now work.

Exercise 5: Line Class

In the final exercise for this chapter we are going to create a Line class. The Line class has a

start- and an end-point. So the Line class should have two Point objects as data members.

This mechanism is called “composition”. See also Figure 3.

Give the Line class the following functionality:

  • Default constructor (set the points to 0, 0).
  • Constructor with a start- and end-point.
  • Copy constructor.
  • Destructor.
  • Overloaded getters for the start- and end-point.
  • Overloaded setters for the start- and end-point.
  • A ToString() function that returns a description of the line.
  • A Length() function that returns the length of the line. Note that you can use the

distance function on the embeddedPoint objects to calculate the length. This

mechanism is called “delegation”.

Use const arguments, const functions and pass objects by reference where applicable.

 

Exercise 5: Line Class

In the final exercise for this chapter we are going to create a Line class. The Line class has a

start- and an end-point. So the Line class should have two Point objects as data members.

This mechanism is called “composition”. See also Figure 3.

Give the Line class the following functionality:

  • Default constructor (set the points to 0, 0).
  • Constructor with a start- and end-point.
  • Copy constructor.
  • Destructor.
  • Overloaded getters for the start- and end-point.
  • Overloaded setters for the start- and end-point.
  • A ToString() function that returns a description of the line.
  • A Length() function that returns the length of the line. Note that you can use the

distance function on the embeddedPoint objects to calculate the length. This

mechanism is called “delegation”.

Use const arguments, const functions and pass objects by reference where applicable.

The Class Concept

Exercise 1: Point Class

Now you must use C++ syntax!!

In this exercise we start creating a Point class with and x- and y-coordinates. This class will

be extended in further exercises.

In Visual Studio, create an empty “Win32 Console Application”. If you don’t check the

“Empty Project” checkbox in the wizard, Visual Studio will generate code for you and will

set the “use pre-compiled headers” on… Pre-compiled headers, which are a Visual Studio

specific option, require special attention in your code and file settings so that is why an empty

project is more appropriate.

First add a header file for the Point class with private members for the x- and y-coordinates.

Do not forget to add the #ifndef/#define/#endif statements to avoid multiple inclusion.

Also make sure you make to following public functionality (see also Figure 1):

  • Default constructor.
  • Destructor.
  • Getter functions for the x- and y-coordinates (GetX() and GetY() functions).
  • Settter functions for the x- and y-coordinates (SetX() and SetY() functions).
  • A ToString() that returns a string description of the point. Use the std::string class as

return type.

+GetX()

+GetY()

+SetX()

+SetY()

+ToString()

-m_x

-m_y

Point

Figure 1: Point Class

Next create the source file that implements the Point class defined in the header file. The

source file must include the header file.

Making the string in the ToString() function, requires conversion of the double coordinates to

a string. Easiest is to use a std::stringstream object and the standard stream operators (as

with iostream) to create the string. This requires the “sstream” header file. Use

the str() function to retrieve the string from the string buffer. The output can be like:

“Point(1.5, 3.9)”

Finally create a test program (separate source file with a main() function) for the Point class.

It should do the following things:

  • Include the point header file. • Ask the user for the x- and y-coordinates using the std::cin object (needs the

“iostream” header file).

  • Then create a Point object using the default constructor.
  • Set the coordinates entered by the user using the setter functions.
  • Print the description of the point returned by the ToString() function.
  • Print the point coordinates using the get functions.

Exercise 2: Distance Functions

In this exercise we are going to add distance functions to the Point class. The distance

functions have the following signature:

double DistanceOrigin(); // Calculate the distance to the origin (0, 0).

double Distance(Point p); // Calculate the distance between two points.

Add the definitions to the header file and implement the functions in the source file. Use

the std::sqrt() function from the “cmath” header file to implement the Pythagoras algorithm.

Extend the main program to print the distance between the origin and another point and test

+GetX()

+GetY()

+SetX()

+SetY()

+ToString()

+DistanceOrigin()

+Distance()

Point

-m_x

-m_y

Figure 2: Point Class with Distance() functions

Input and Output

Exercise 1

Create a C-program that reads the characters from the keyboard and shows them on

screen (the inputted characters should only be displayed when the user hits ‘enter’, line

by line).

When ^A is entered, the program must end properly. Then the following message will

appear: “CTRL + A is a correct ending.”

Tip: getchar() reads and putchar() writes the type int. The value of ^A is 1.

Exercise 2

Alter the last program of exercise 1 in such a way that the output doesn’t go to the screen

but is written to a file. The file to write to must be specified by the user.

Structures

Write a C-program that prints the contents of a struct called Article. An Article has the

following characteristics:

  • Article number
  • Quantity
  • Description (20 characters)

The test program must create an Article of which the contents are assigned at

initialization level.

Printing the Article is done with a Print() function. This function gets the address of the

structure as a parameter.

Tip: Suppose that p is the pointer to the structure. It will allow the fields to be printed

by (*p).fieldname or p->fieldname.

Pointers and Arrays

Exercise 1

Try to create a function Swap(). This function must exchange the value of two variables.

For example: if i=123 and j=456, then i=456 and j=123 after the Swap() function has

been called. The variables i and j are declared, initialised and printed in the

function main(). This problem can be solved by using pointers as arguments for

the Swap()function.

Exercise 2

The following program reads a string with a 30 character maximum. Implement

the Length() function. The function Length() must determine the length of the string.

Give Length() the address of the array as argument.

Note: your Length() function should be similar to the built-in strlen() function so your

job is to mimic that function without using it.

EOF is used in the function main(). This means End-of-File and is discussed later on in

this document.

In DOS, EOF can be entered by the key combination Ctrl-z (often written as ^Z). With

^Z (Say: control Z) is meant pressing the control-key and the z-key simultaneously.

The Preprocessor

Write a C-program that contains two print macro calls. The first prints the variable a, the

second prints the variables a and b. Printing happens by the use of the PRINT1 and

PRINT2 macros that accept arguments. These macros must be defined in an include-file.

The variables a and b gets their value in the function main().

Name the program “Macro.c” and the include-file “Defs.h”. Don’t forget to implement

the mechanism to avoid multiple inclusion of the header file.

Artificial Intelligence

The objective of this homework is to build a hand gesture classififier for sign language. We will be using

Google Colaboratory to train our model (set up instructions at the end). The dataset will be in the form of

csv fifiles, where each row represents one image and its true label.

We have provided the skeleton code to read in the training and testing datasets. Before you begin coding, go

through the provided code and try to fifigure out what each function is responsible for. Most of the functionalities are

implemented in the SignLanguage class. Below are brief descriptions of each function and what is expected of you.

  • create model(self): You will generate a keras sequential mode here. Make sure to set the self.model

variable with your compiled sequential model.

  • prepare data(self, images, labels): Mainly this splits the data into training and validation sets. You may

choose to normalize or downsample your data here, as well.

  • train(self, batch size, epochs, verbose): This method invokes the training of the model. Make sure to

return the generated history object. Your model will be trained for a max of 50 epochs during grading. Make

sure you are using the input parameters (batch size, epochs, verbose)

  • predict(self, data): This method will be invoked with the test images. Make sure to downsample/resize the

test images the same way as the training images, and return a list of predictions.

  • visualize data(self, data): Nothing to do here. This is solely to help you visualize the type of data you are

dealing with.

  • visualize accuracy(self, history): Nothing to do here. It plots out the accuracy improvement over training

time