Chapter 12 - Worked Exercises 1
Exercise 1 - Vector
Preamble
C++ provides to us in the standard library a vector class, which is a dynamically sized array that can grow in size as we add elements to it.
In this example we'll learn how to implement our own vector class that mimics some of the behaviour of the std::vector class.
Part 1
Create a class VectorInt that is like a vector class that stores a collection of ints.
The class should have a private member variable for a dynamic array of ints, call this member variable values.
The class should also have two member variables of type int:
One called
capacity, representing the size of thevaluesarray.One called
size, representing the number of elements currently stored by theVectorInt.
Part 2
Provide a default constructor that creates a dynamic array for 50 elements.
Provide a constructor with one int argument for the number of elements in the initial dynamic array.
Provide member functions capacity, size that simply return the capacity and size of the vector.
Provide a destructor to ensure that all dynamically allocated memory is cleaned up when the vector is destroyed.
Part 3
Create a member function push_back which accepts an integer value, and adds it to the end of the values array. The size variable should also be updated to account for this.
Part 4
When there is no more room in the values array, then a new dynamic array with twice the capacity of the old dynamic array is created.
The values of the old array are copied into the new dynamic array, then the element is added to the end of it.
The size and capacity variables should be updated accordingly.
Part 5
Implement a copy constructor, and a suitable overloading of the assignment operator to ensure that deep copies of the vector are made when these are invoked.
Provide two examples in your main function showing when each of these copy methods are invoked.
Part 6
Create a const char* member variable called contents_str.
Now create a conversion operator that converts the VectorInt into a const char* type. You will need to use the member variable contents_str to store the string (character array) that is to be returned by the function.
The conversion operator should return the contents of the VectorInt in the following format:
[ a, b, c, d ... ]
where a, b, c, d are elements of the VectorInt.
This should allow you to pipe a VectorInt object to std::cout, do this in your main function.
Exercise 1 - Rational Numbers
In this exercise we will explore why operator overloading is useful. You will first create a class without operator overloading, where the convenience of operator overloading will later become apparent.
Preamble
In mathematics, a rational number is a number that can be expressed as a fraction of two integers, a numerator and a denominator.
For example, the numbers 1/2, 2/3, 15/32, 65/4, 16/5 are all rational.
Part 0
Create a Rational class that will be used to represent rational numbers. The class is composed of two integers representing the numerator and denominator respectively.
In each of the subsequent parts below, implement a driver main function to test the functionality of your implementation of the Rational class.
Part 1
Provide a constructor to create a Rational object from two int parameters corresponding to the numerator and denominator respectively.
Since all integers are also rational numbers (as in 2/1 or 17/1), provide a constructor that takes int parameter called whole_number, and constructs a Rational object with a denominator of 1.
Provide a default constructor that initialises an object to value 0 (i.e. 0/1).
Part 2
Provide member functions add, sub, mul and div that takes another Rational object as a parameter, and returns a new value of type Rational.
You will find the following formulas useful for defining your functions:
Addition:
a/b + c/d = (a * d + b * c) / (b * d)Subtraction:
a/b - c/d = (a * d - b * c) / (b * d)Multiplication:
(a/b) * (c/d) = (a * c) / (b * d)Division:
(a/b) / (c/d) = (a * d) / (c * b)
Provide member functions less and equals that takes another Rational object as a parameter, and returns a bool value.
You will find the following formulas useful for defining your functions:
Less than:
(a/b) < (c/d) means (a * d) < (c * b)Equals to:
(a/b) == (c/d) means (a * d) == (c * b)
Part 4
Overload the increment and decrement operators (both prefix and postfix) such that it increments or decrements the rational number by 1.
For decrementing, this would be subtracting the numerator by the denominator. For example, decrementing 1 from 15/8 would result in 7/8.
Conversely, incrementing is adding denominator to the numerator.
Part 5
Using the member functions you have created in Part 2, overload all the following operators so that they correctly apply to the type Rational:
==<<=>>=+-*/
Detour - Greatest Common Divisor
The greatest common divisor (GCD) of two number is the largest number that divides them both.
For example, common divisors of 20 and 15 are 1, 3, and 5. Hence, the GCD is 5, as it is the largest of all the divisors.
Create a function that returns the GCD of two numbers:
int gcd(int x, int y) {
// your code here
}Part 6
You may notice that our current Rational class does not attempt to simplify its fraction. For example multiplying Rational(1, 2) with Rational(2, 1) yields Rational(2, 2) instead of Rational(1, 1).
Although the answers are semantically the same, this means that doing many operations over may result in seemingly large fractions, and may even lead to overflow.
Use the gcd function you have created in the previous section to simplify the fraction in the constructor of the Rational class.
Show an example in your main function that implementing the above step solves the issue mentioned.
Exercise 3 - Freeing Memory
For each of the below examples, write appropriate code that would free all memory that was dynamically allocated. If no freeing is required, state so.
Question 1
int* a = new int(10);
int b = 5;Question 2
int* a = new int;
int* b = new int;Question 3
int* a = new int[10];
int* b = new int[12];
for (int i = 0; i < 10; i++) {
a[i] = 4;
}Question 4
int** a = new int*[50];Question 5
int** a = new int*[5];
for (int i = 0; i < 5; i++) {
a[i] = 0;
}Question 6
int** a = new int*[16];
for (int i = 0; i < 16; i++) {
a[i] = new int(2);
}Question 7
int* a = 0;
int* b = 0;
int c = 10;Question 8
int* a = new int(5);
int* b = a;
int* c = new int(*b);Exercise 4 - String
Preamble
Much like the VectorInt class that you have made in Exercise 1, you will now implement a String class that behaves similar to the std::string class of the standard library.
Remember that the point of the exercise is to not use any standard libraries, unless explicitly specified.
Part 0
Refresh your memory by reviewing the C-style Character Strings section of the textbook.
You are allowed and suggested to use the following standard library functions found in the <string.h> header in your code:
strcpy()- documentationstrlen()- documentationstrcat()- documentation
Part 1
Create a String class that stores a string as a character array (char*) in a member variable called contents.
Create a constructor that accepts a const char* parameter, and copies the contents from said parameter into its contents member variable.
The character array for the
contentsmember variable should be dynamically allocated.You will find the functions
strcpy()andstrlen()helpful.
Create a suitable destructor that frees the memory allocated by contents.
Part 2
Implement a conversion operator that would convert a String object into a const char*. This would be simply returning its contents member variable.
Explain why this allows you to now do the following:
String myStr = "Hello World!"
std::cout << myStr << std::endl; // Prints "Hello World!"Part 3
Overload the addition operator (operator+) so that you are able to concatenate two String objects together.
String myStr = "Hello World!";
String myStr2 = " Goodbye!";
String myStr3 = myStr + myStr2;
std::cout << myStr3 << std::endl; // Prints "Hello World! Goodbye!"Overload the addition operator (operator+) so that you are able to concatenate a String object with a const char* object together.
String myStr4 = "Good ";
String myStr5 = myStr + " morning!";
std::cout << myStr5 << std::endl; // Prints "Good morning!"Part 4
Implement a suitable copy constructor for the String class. Show in your main program an example of an issue that is addressed by the copy constructor that you've implemented.
Implement a suitable copy assignment operator for the String class. Show in your main program an example of an issue that is addressed by the copy constructor that you've implemented.
Solution
Last updated
Was this helpful?