Month: January 2023

Finding water level changes via satellite imagery

Please read this assignment carefully.
This coursework is concerned with the creation of a library to analyse data from different instruments onboard
a satellite. The instruments provide daily updates from a piece of land that can be used to track
water levels at different locations.
This assignment asks you to work collaboratively within your team to create a package. For that you will
need to write some code for querying, loading and analysing a dataset about different portions of land in
a map. We will describe how the code must behave, but it is up to you to fill in the implementation. The
package needs to follow all the good practices learnt in the course, that is, the package should: be version
controlled; include tests; provide documentation and doctests; set up command line interfaces; and
be installable. Besides this, you will also need to modify an existing implementation of a provided script
to make it more readable, more efficient, and measure its performance.
The collaboration aspect should be organised and managed using GitHub.
The exercise will be semi-automatically marked, so it is very important that your solution adheres to the
correct interface, file and folder name convention and structure, as defined in the rubric below. An otherwise
valid solution that doesn’t work with our marking tool will not be given credit.
For this assignment, you can use the Python standard library and other libraries you may wish to use (but
make sure they are clearly set as dependencies when installing your package). Your code should work with
Python 3.9.
First, we set out the problem we are solving. Next, we specify the target for your solution in detail. Finally,
to assist you in creating a good solution, we state the marking scheme we will use.
1 Background information
The Irish Space Agency has launched Aigean, an Earth observation satellite to monitor an area around
Lough Ree. Recently, rainfall has decreased in the area, and during the latest years droughts have become
more frequent and more severe. With the instruments on board Aigean the scientific community will be
able to obtain better data about the water levels and the erosion of the land, and therefore will be able to
generate more accurate predictions.
However, the Irish Space Agency sadly hasn’t provided any software tools to do this analysis!
Thankfully, Aoife O’Callaghan, a geology PhD student at the Athlone City Institute, has set the objective
to solve this problem by creating an open-source package to analyse Aigean data. Aoife has some ideas of
what she would like the package to do, but she doesn’t have a research software development background
beyond how to install and use Python libraries. That’s why Aoife has contacted you!
You and your group members agree this is a great tool to offer to the community and have decided to put all
your brains together to come up with an easy-to-use Python library to analyse and visualise Aigean satellite

What do we know? What do we have? What do we want?
1. Aigean has multiple instruments, as an starting point we only need to focus on the imagers and the
2. There are three imagers on board of the spacecraft. Their only differences are in their resolution (how
much area they cover per pixel) and their field-of-view (how much they can see in a single image).
3. The three imagers are called: Lir, Manannan and Fand. •Lir has the largest field-of-view, but the smaller resolution with a pixel size of 20 m per pixel; •Manannan provides a smaller field-of-view with a better resolution of 10 m per pixel; and •Fand has the smallest field-of-view but a very high resolution of 1 m per pixel.
4. The radar is called Ecne and it provides three measurements for the deepest areas in the region.
5. Each instrument provides data in a different format, but the imagers share a common set of metadata.
6. A number of images are taken every day, however not all the land is fully covered in a single day, it
depends on the satellite orbits. Ecne, however, takes always measurements of the same points.
7. All the data is available at the Irish Space Agency webservice archive.
8. The Python library – aigeanpy – should be able to query, download, open, process and visualise the
satellite images.
9. We want to create three command line tools to provide access to some functionality from outside
10. We have a script from a post-doc of Aoife’s group that implements the so-called k-means algorithm for
clustering data points. We want to include it in our library too! It will help people to analyse different
land areas based in their parameters.
11. We are also interested on how to make our code, specifically the k-means algorithm, more efficient.
This will be used to analyse Ecne’s data.
12. We want this tool to be used by any researcher, so it needs to be easy to install and use. This includes
having good documentation about how to use it and how to acknowledge it in the publications that
benefit from it.
13. And we also want to make it easier to others to contribute so we need to provide information about
how we would like others to contribute.
Let’s look at what we’ve got access to already:
1.1 The data archive webservice
The Irish Space Agency data archive is located at: and
their main page provides some information about how to query this service.
The website offers two services. One is used to query the catalogue, and the other to download a file from
the archive.
The results from the query service are provided as JSON files with the properties of the observations found
in the specified time range (and instruments). These files include information about the date and time of
the observations, the instrument used, the field of view observed and the filename where that observation is
stored. We can download that files using the filename as an argument to the download service. The format
from the observation files vary depending on the instrument (specified in the following section).
Read the information on the archive website to understand how to query the service, what parameters are
accepted and what are the defaults.
We need to create a set of tools within the Python package to query and download the files. They need to
be available from and They must accept
all the parameters listed on the website. Additionally, the download_isa need to allow the user to specify
where to download the file (save_dir).

1.2 Different instruments, different file types
Data from each instrument is provided in a different type of file.
Lir uses the Advanced Scientific Data Format (ASDF). The asdf Python library can read them and extract
the data and metadata from these files.
Manannan uses Hierarchical Data Format 5 (HDF5). As with the asdf, this type of file contains the data
and the metadata together. The h5py Python library can load them.
The Fand instrument stores the data in npy format and the metadata in JSON files. npy files can be read
from NumPy’s load and the Python Standard Library provides support to load JSON files. The archive
provides that pair of files in a single zip file (for which Python Standard Library also provides a module to
load: zipfile).
Finally, the Ecne instrument doesn’t take images, but infers some measurements of the 300 deepest areas in
the region. The measurements are turbulence, salinity and algal density for these points. They are stored
in CSV.
􀄎 Ideally a user shouldn’t need to unzip the file before loading it with the library. The io.BytesIO
class can help you to load the file in memory. Take a look at how it’s used on the exemplar at the
beginning of our course notes.
1.2.1 Getting the coordinates right
Arrays are stored in Python as (rows, columns). However, we normally refer to places in a map as (x, y)
coordinates (with x running from left to right, and y running from bottom to top). Also when displaying an
image in matplotlib with imshow, by default, you’d get the axis as its origin is in the top-left corner and
positive y-values going downwards. For this library, we will need to manage two type of coordinate systems:
pixels and earth.

Figure 1: Difference between the two coordinate systems. The plot in the left shows the default when
visualising an array, the (0, 0) is on the top left corner. On the right, the same array is shown as a map,
which a set of (x, y) coordinates are represented within a pixel. In this case each pixel corresponds to 10
meters and the origin is within the second row, and the first column.
To ease the conversion between the coordinate systems you’ll need to create two helper functions, which are
called earth_to_pixel and pixel_to_earth.

Each image will come with an array of a particular size (and shape) and the metadata will provide the
resolution (in meters per pixel), the earth x- and y-coordinates (in meters) as the (lower, upper)
boundaries for each axis. The field of view (i.e., the difference between the boundaries) divided by the
resolution should give you the shape of the array (in the (columns, rows) order).

Core Scanner

The goal of this project is to build a scanner for a version of the Core language, a pretend
language we will be discussing in class.
For this project you are given the following:
ˆ \3341 Project 1.pdf” – This handout. Make sure you read it completely and handle all
requirements in your implementation. You are encouraged to post any questions on
ˆ \main.c”, \core.h”, \scanner.h”, \scanner.c” – I have outlines the project in this les,
and give you some of the code you will need. Make no changes to to \core.h” le.
You can make changes to \main.c” as long as those changes do not change break my script.
ˆ You may create additional les to contain any additional classes or methods you want
to create.
ˆ \” – This is a script I wrote to help you test your project. It is very similar
to the script that will be used to grade your project, so if your project works correctly
with this script you are probably doing well. The only guarantee I give is that this
script will work on stdlinux.
ˆ Folder \Correct” – This contains some correct inputs and their expected outputs. The
\” script will test your code against these examples.
ˆ Folder \Error” – This contains some inputs that should generate error messages. The
\” script will test your code against these examples.
The following are some constraints on your implementation:
ˆ Do not use scanner generators (e.g. lex, ex, jlex, j ex, ect) or parser generators
(e.g. yacc, CUP, ect)
ˆ Use only the standard libraries of C. This is the reference I like to use:
Your submission should compile and run in the standard linux environment the CSE
department provides (stdlinux). I will leave it up to you to decide what IDE you will use or
if you will develope your code locally or remotely, but as a nal step before submitting your
code please make sure it works on stdlinux. Use the subscribe command – make sure
you are subscribed to GCC-10.1.0. The graders will not spend any time xing your
code – if it does not compile on stdlinux, your project will not be graded and you
will get a 0.

Your Scanner
You are responsible for writing a scanner, which will take as input a text le and output a
stream of \tokens” from the core.h enumeration. You scanner must implement the following
ˆ scanner open and scanner close: These functions open the le, nd the rst token, and
release memory when we are done scanning.
ˆ currentToken: This function should return the token the scanner is currently on, with-
out consuming that token.
ˆ nextToken: This function should advance the scanner to the next token in the stream
(the next token becomes the current token).
ˆ getId: If the current token is ID, then this function should return the string value of
the identi er. If the current token is not ID, behavior is unde ned.
ˆ getConst: If the current token is CONST, then this function should return the value
of the constant. If the current token is not CONST, behavior is unde ned.
All of these functions will be necessary for the parser you will write in the second project.
You are free to create additional functions.
To make things easier for you, you may assume no token is made of more than 20
characters. Also, I suggest using calloc to allocate memory, instead of malloc.
The input to the scanner will come from a single ASCII text le. The name of this le will
be given as a command line argument to the main function.
The scanner should process the sequence of ASCII characters in this le and should
produce the appropriate sequence of tokens. There are two options for how your scanner can
(1) the scanner can read the entire character stream from the le, tokenize it, stores all the
tokens in some list or array and calls to currentToken and nextToken simply walk through
the list
(2) the scanner reads from the le only enough characters to construct the rst token, and
then later reads from the le on demand as the currentToken or nextToken functions are
Real world scanners typically work as described in (2). In your implementation, you can
implement (1) or (2), whichever you prefer.
Once your scanner has scanned the entire le, it should return the EOS token (End Of

Invalid Input
Your scanner should recognize and reject invalid input with a meaningful error message. The
scanner should make sure that the input stream of characters represents a valid sequence of
tokens. For example, characters such as ` ‘ and ‘%’ are not allowed in the input stream. If
your scanner encounters a problem, it should print a meaningful error message to standard
out (please use the format “ERROR: Something meaningful here”) and return the ERROR
token so the main program halts.
The Language
The Core language consists of 4 kinds of strings, which you will need to tokenize:
ˆ Keywords:
and begin do else end if in integer
is new not or out procedure record then while
ˆ Identi ers:
Begins with a letter (uppercase or lowercase) followed by zero or more letters/digits.
Refer to this regular expression once we cover regular expressions:
(aj : : : jzjAj : : : jZ)(aj : : : jzjAj : : : jZj0j1j : : : j9)*
ˆ Constants:
Integers from 0 to 1009 (inclusive)
ˆ Symbols:
+ – * / := = < : ; . , ( ) [ ]
Your scanner walk through the input character stream, recognize strings from the lan-
guage, and return the appropriate token from the enumeration in \” or \”.
If there is any situation in which it is unclear to you which token should be returned, please
ask for clari cation on Piazza.
Write your scanner with these rules in mind:
1. The language is case sensitive, and the keywords take precedence over the identi ers.
For example, \begin” should produce the token BEGIN (not ID), but \bEgIn” should
produce the token ID.
2. Strings in the language may or may not be separated by whitespaces. For example the
character stream may contain the string \x=10″ or the string \x = 10″, and both of
these should generate the token sequence ID EQUAL CONST.
3. Always take the greedy approach. For example, the string \whilewhile” should produce
an ID token instead of two WHILE tokens, string “123” should produce a single CONST
token, and string \:=” should produce ASSIGN.

4. Keyword/identi er strings end with either whitespace or a non-digit/letter character.
For example:
(a) the string \while (” and the string \while(” should both result in the WHILE and
LPAREN tokens.
(b) the string \while 12″ should result in the WHILE and CONST tokens, but the
string \while12″ should result in the ID token.
5. Constant strings end with any non-digit character. For example:
(a) the string \120while” or \120 while” should result in the CONST and WHILE
6. Symbols may or may not be separated from other strings by whitespace. For example:
(a) String \++while<= =12=” should result in the token sequence ADD ADD
Let me know if you think of any situations not covered here.
Testing Your Project
I have provided some test cases. For each correct test case there are two les (for example
4.code and 4.expected). On stdlinux you can redirect the output of the main program to a
le, then use the di command to see is there is any di erence between your output and the
expected output. For an example of how to do this you can take a look at the script le
The test cases are weak. You should do additional testing with your own test cases. Feel
free to create and post additional test cases on piazza.
Project Submission
On or before 11:59 pm January 27th, you should submit to the Carmen dropbox for Project
1 a single zip le containing the following:
ˆ All your .java or .py les.
ˆ An ASCII text le named README.txt that contains:
{ Your name on top
{ The names of all les you are submitting and a brief description stating what each
le contains
{ Any special features or comments on your project
{ Any known bugs in your scanner  If the time stamp on your submission is 12:00 am on January 28th or later, you will
receive a 10% reduction per day, for up to three days. If your submission is more than 3
days late, it will not be accepted and you will receive zero points for this project. If you
resubmit your project, only the latest submission will be considered.
The project is worth 100 points. Correct functioning of the scanner is worth 65 points. The
handling of errors is worth 20 points. The implementation style and documentation are
worth 15 points.

Data Engineering

Answer these questions in best of your abilities within 24 hours. If you are stuck on a technical aspect, write down in words how you would go about answering this questions and what other information would you need.

  1. Attached is a sample dataset with 100,000 rows of random placements, and media exposure by impressions. What queries would you use to analyze the data? (Hint: you need to think about cleaning the data first. Common data problems include duplicates, missing, errors in the data)


  1. Now that you identified issues with the data, do you notice anything particular about this dataset? What queries would you use to investigate? (Hint: think about what you know about digital marketing and do you think these would be good exposures?)


  1. Segment the media exposures into 5 groups. What queries would you use to help you with this? Create a histogram in your answer.


  1. How many green T-shirts do you think are sold in a year? (This is an open ended question, let us know how you would go about this figure)


Exercise 1: CAD and Container Namespaces
To avoid name conflicts, programmers can place their classes in a namespace. For example the standard library is placed in a namespace called std. You should put your classes in your own namespace. Thus place the CAD classes (Shape,Point, Line, etc) in the namespace: YourName::CAD Place the container classes (Array) in the namespace: YourName::Containers Now access the classes in your own namespace using:
• Full class name including namespace for the Point used in the Array class. Note that you can use only the CAD part of the namespace without the YourName part because the Point is also in the YourName namespace.
• In the main program, the full namespace for Point class.
• In the main program, using declaration for using a single class (Line).
• In the main program, using declaration for a complete namespace (Containers).
• In the main program, using the Circle class by creating a shorter alias for the YourName::CAD namespace.

The Free Store

Exercise 1: Dynamically Creating Objects
Until now, we created objects on the stack. The stack is limited in size thus when creating many objects, the stack will overflow. Also arrays created on the stack can only have a fixed size determined at compile time. To overcome these problems we have to create objects on the heap using new. In the main program, create Point objects on the heap with new using the default constructor, constructor with coordinates and the copy constructor and assign it to pointer (Point*) variables. Note that you can’t directly pass a pointer variable as argument to the copy constructor. The pointer must first be dereferenced when passing it to the copy constructor. (Point* p2=new Point(*p1)). Next call the Distance() function on the pointers and try to send the Point pointers to cout. You need to dereference the pointer when passing it as argument. Don’t forget to delete the object created with new. Test the main program. Next, we will create an array of points. First ask the user for the size of the array and read it using cin. Then try to create an array on the stack using the entered size. You will see a compiler error. Arrays on the stack must have the size set at compile time. Now create the array on the heap using new. Can you use other constructors than the default constructor for the objects created in the array? Don’t forget to delete the array after use. Don’t forget the square brackets when deleting arrays! Some C++ compilers (e.g. GCC) support variable length arrays (VLA) where the size can be determined at run-time. However this is a C99 feature that is not in the C++ standard. Because VLA is not in the C++ standard you should avoid its usage since it will lead to less portable code.

Exercise 2: Creating Array of Pointers
In this exercise we make it a little more complex. With an array of Points, all points are created with the default constructor. When creating an array of pointers, each element in the array must be created separately but can be created with other constructors than the default constructor. Thus creating an array of pointers is a two step process:
• Create an array of Point pointers with 3 elements on the heap.
• Create for each element in the array a point on the heap.
• Iterate the array and print each point in the array.
• Iterate the array again and delete each point in the array.
• Delete the array itself.
Also make a drawing of the memory layout.

Exercise 3: Creating Array Class
It is easy to forget to delete memory created with new. A good practice is to let a class manage memory. Then the client of that class does not have to manage memory and can’t forget to delete memory. So instead of creating a C array with new, you can use an array class that handle memory for you. In this exercise we are going to create an array class for Point objects (see Figure 5):
• Add a source- and header file for the Array class to your current project.
• Add a data member for a dynamic C array of Point objects (Point* m_data).
• Add a data member for the size of the array.
• Add a default constructor that allocates for example 10 elements.
• Add a constructor with a size argument. The implementation should allocate the number of elements specified by thesize input argument.
• Add a copy constructor. Keep in mind that just copying the C array pointer will create an Array object that shares the data with the original Array object. Thus you need to allocate a new C array with the same size and copy each element separately.
• Add a destructor. It should delete the internal C array. Don’t forget the square brackets.
• Add an assignment operator. Keep in mind you can’t copy only the C array pointers just as in the case of the copy constructor.
• Also don’t forget to delete the old C array and allocate new memory before copying the elements. This is because C arrays can’t grow.
Further check if the source object is not the same as the this object. If you don’t check it, then a statement like arr1=arr1 will go wrong. The internal C array will then be deleted before it is copied.
• Add a Size() function that returns the size of the array.
• Add a SetElement() function that sets an element. When the index is out of bounds, ignore the “set”. We will add better error handling later.
• Add a GetElement() function. You can return the element by reference since the returned element has a longer lifetime than the GetElement() function. When the index is out of bounds, return the first element. We will add better error handling later.
• You can also add a square bracket operator. Return a reference so the [] operator can be used for both reading and writing elements. When the index is out of bounds, return the first element. We will add better error handling later.
Point& operator [] (int index);
• In the main program, test the Array class.

Basic Operator Overloading

Exercise 1: Adding Operators to the Point class
By supporting operators, you can make your classes easier and more natural to use. However you must not “overuse” operators. Only use operators if the functionality of the operator is clear without reading documentation. Thus adding mathematical operators to a complex number class is good but using a + operator with a double as an argument on a point to increase the x-coordinate is questionable. So use operators with care. In this exercise we add a few operators to the Point class. Most operators do not change the original objects but return the result as a new object. Normally only the = operator and += and variants change the original object. Add the following operators:

Exercise 2: Ostream << Operator
It would be nice if you could send a point or a line directly to the cout object without calling the ToString() method, just as with the primitive types. This is possible by adding a << operator function that has on the left an std::ostream and on the right the point or line object. Since you can’t add a member function to the std::ostream class, you have to create it as a global function (outside the class definition, but inside the class header file):
ostream& operator << (ostream& os, const Point& p); // Send to ostream.
The implementation uses the << operator to send data to the os input argument. Since it is a global function, you can’t access the private members of Point. To simplify things, you can use the ToString() method of Point to get the string to send to the os argument. Also create a similar << operator for printing lines (and circles if you made a circle class). Adapt the test program to test the << operator for points and lines.

Exercise 3: Constructors as conversion operator
In this exercise we are going to do a little experiment. First add to the Point class a constructor that accepts one double as an argument. The implementation should set both the x- and y-coordinate to this value. Next try the following code in the test program:
Point p(1.0, 1.0);
if (p==1.0) cout<<“Equal!”<<endl;
else cout<<“Not equal”<<endl;
Will this code compile and can you explain why? It turns out that the Point constructor with the single double argument is implicitly used to convert the number in the if statement to a Point object. Thus constructors are used as implicit conversion operators. To prevent the usage of constructors are implicit conversion operators, declare the constructor as explicit:
explicit Point(double value);
Now try to compile the program again and you will see that now the if statement gives a compiler error. You can still use the constructor as conversion operator but then explicitly:
if (p==(Point)1.0) cout<<“Equal!”<<endl;

Exercise 4: Friends
Normally, only member functions of a class can access the private members of that class. Global functions and other classes can’t access the private members of that class. You can make an exception on that rule by declaring certain functions or classes as friend. For example the << operator for sending the point or line to the std::ostream class had to be a global function and thus can’t access the private members. Move the << operator of Point and Line inside the class definition and declare it as friend. The function remains a global function but it can now access the data members directly without the need for calling the getters or ToString() function. Normally, friends are to be avoided because it violates the data hiding principle. But in case of global operator functions it makes sense because you would actually want to make those global operator functions as member function but this was not possible.

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.


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: