Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit

EXAMINATION PERIOD 2 2022

5CCYB041 Object-Oriented Programming

Part A

Compulsory part. Answer all questions in Part A.

Question A.1

(a) Briefly explain what is meant by:

• a public method

• a protected data member

• a private static data member

(b)  In the following code snippet, what does the const keyword mean?

1    const   double   pi  =   3 . 14159265359;

(c)  In the following code snippet, what does the const keyword mean?

1   double   compute _mean   ( const   std::vector <double >&   array);

(d)  In the following code snippet, what does the const keyword on line 3

mean?

1    class   Square   {

2            public :

3                     float   get _ size()   const   {   return   _x;  }

4                     void     set _ size( float   s)  {   _x  =   s;  }

5            private :

6                     float   _x; 7   };

Question A.2

The following is a UML diagram of a class hierarchy for handling computer pointing devices. These could implement the low-level functionality (software drivers) necessary for the computer to use a mouse, whether connected via PS/2 (old-style connector), USB, or BlueTooth.

It demonstrates how computer peripherals (e.g. a mouse) can share generic properties and behaviours despite their different hardware implementations. The implementation for using the device depends on its specific type (PS/2, USB or BlueTooth), yet the interface provided is identical from the program- mer’s point of view.

Write class definitions for the Mouse and USBMouse classes in the diagram. You only need to include the data members and member functions listed in the diagram (you do not need to provide any implementations for the member functions).

Question A.3

Write a function that evaluates the following equation:

N − 1

s = b(i) × x(N 1 i),

i=0

where b and x are two arrays and have the same length (equal to N).  The    function should take two input arguments (b and x) of type std::vector<double>. If b and x have different lengths, an exception should be thrown.  The func-    tion should return s as a variable of type double.  Make sure to add all the    necessary include statements.

Question A.4

A developer decides to test the C++ random number generator function and assess the distribution of generated samples. They write the following code to sample many random decimal values within a user-defined range, then bin

and display the result.

1   # include   < iostream >

2   # include   < vector >

3   # include   <cmath >

4

5   template   < class   DTYPE >

6    class   RandomNumber 7   {

8   public :

9        RandomNumber(DTYPE   min _ value ,  DTYPE   max _ value)

10             _min _ value   =  min _ value;

11             _max _ value   =  max _ value;

12        }

13        DTYPE   Get()   {

14            DTYPE  v=(DTYPE)rand()/( RAND _ MAX) 15                 *   ( _max _ value   -   _min _ value)  +  16                 _min _ value;

17            return   v; 18        }

19   private :

20        int   _min _ value;

21        int   _max _ value; 22   };

23

24    int  main()

25   {

26        //   Set   the  min   and  max   value   for   the   generator

27        int   min _ value   =   - 10;

28        int   max _ value   =   10;

29        int   total _ sample   =   1000;

30        //   Set   the   value   to   generate   to   stop   the   process

31        float   stopping _ value   =   0;

32        //   Set   the   variable   to   store   the   sample   occurrence

33        int   range   =  max _ value   -  min _ value; 34

35        //   Set   and   initialise   bin   array

36        int   binned _ values[range];

37        for   ( int   i  =   0;   i   <  range;   i++)

38            binned _ values[i]  =   0;

39

40      //   Generate   a   random   value

41        RandomNumber *randNumber =

42            new RandomNumber(min_value , max_value); 43

44        // Sample values until reaching stopping criteria

45        for ( int i = 0; i < total_sample; i++) {

46            float val = randNumber ->Get();

47            // Compute the corresponding bin and update its value

48             int bin = floor(val) - min_value;

49            // cout << bin << " " << val << endl ;

50            binned_values[bin] += 1;

51        }

52

53        // Display the number of occurrence in each bin

54        for ( int i=0; i<range; ++i) {

55             cout << " [ " << i+min_value << " : " ;

56             cout << i+min_value+1 << "]␣ = ␣ " ;

57             cout << binned_values[i]/( float )total_sample << endl; 58        }

59        return 0; 60   }

The code contains five errors.  Identify these errors and explain how to fix them.

Question A.5

Examine the following code.  A class Trajectory1D is defined by its list of

1D positions representing the displacement of an object over time. This code

contains 5 errors. Identify, describe and correct those errors.

1   # include   < iostream >

2   using   namespace   std; 3

4    class   Trajectory1D   {

5   protected :

6            vector <double >   _ positions; 7

8   public :

9            Trajectory1D()   {}

10

11            ∼Trajectory1D()   {

12                     delete   _ positions; 13            }

14

15            void   setPositions( const   vector <double >  &positions)   const   { 16                     _ positions . clear();

17                     for   ( int   i   =0;   i   <  positions . size();   i++) 18                              _ positions[i]  =  positions[i];

19            }

20

21            void   display()   const   {

22                     for   ( int   i  =   0;   i   <   _ positions . size();   i++)

23                              cout   <<   _ positions[i]   <<   endl; 24            }

25   };

26

27    int  main()   {

28            vector <double >  positions;

29            positions . push _ back (1);

30            positions . push _ back (1 . 3);

31            positions . push _ back (11 . 5);

32            Trajectory1D   t;

33            t - >setPositions(positions);

34            return   0; 35   }

Part B

Answer any 2 of the following 4 questions.

Question B.1

As part of a project, a student would like to evaluate which of two down- sampling techniques best preserve the information contained in a 1D signal containing integer values.

The first down-sampling technique simply extracts every other value.  The intensity in the down-sampled signal D at position i is equal to the intensity in the original signal O at position 2i, so that D[i] = O[2i]. An example is shown below:

 

The second down-sampling technique extracts the mean value from a 3-point neighbourhood so that the value D[i] is equal to mean intensity of O[2i + j] with j ∈ [ −1, 0, 1].

To compute the information H within the signal, the student decides to use Shannon’s entropy theorem:

H = p(e) × log(p(e))

e

where e denote an event and p(e) its probability of occurrence. In the present case, the events correspond to the discretised signal values. In other words, each p(e) term in the equation above corresponds to the frequency of oc- curence of each possible value for the signal.  If the value 1 occurs 11 times

in a signal of length 100, then its corresponding p(e) = 11/100 = 0.11. They started to implement the solution below but did not complete it.

1   # include   < iostream >

2   # include   < vector >

3   # include   < algorithm >

4   # include   < cstdlib >

5

6    class   Signal{

7   public :

8        Signal( unsigned   int   d)   :   _ data   (d)  {  } 9

10        void   Random( int  min _val ,   int   max _ val)  {

11            for   ( unsigned   int   i=0;   i   <  GetDim();   ++i)  {

12                 _ data[i]  =  min _ val   +   rand()  %   (max _ val   -  min _ val);

13            }

14        };

15

16        float   GetEntropy()   {

17            //   Extract   the  min   and  max   value   intensity   in   the   signal

18             int  min _ value ,  max _ value;

19            GetIntensityRange   (min _ value ,  max _ value); 20

21            //   Create   an   histogram   to   store   all   occurence

22             int   histo _ dim   =  max _ value - min _ value;

23             std::vector < int >  histogram   (histo _ dim ,   0); 24            //   Accumulate   each   intensity s   occurrence :

25            for   ( unsigned   int   i=0;   i   <  GetDim();   ++i){

26                 histogram[ _ data[i] - min _ value ]++; 27            }

28            //   Compute   the   entropy

29            float   entropy   =   0 . 0; 30            //   TO   COMPLETE

31        }

32

33        Signal   Downsample()   {

34            Signal   new _ signal   ((GetDim ()+1)/2);

35            for   ( unsigned   int   i=0;   i   <  new _ signal . GetDim();   ++i){

36                 new _ signal . _ data[i]  =   _ data[2*i]; 37            }

38            return   new _ signal;

39        }

40

41   protected :

42        std::vector < int >   _ data; 43   };

44

45    int  main()

46   {

47      Signal sig(50);

48      sig .Random(0,63); 49

50      std::cout << "Original␣entropy␣ value ␣ = ␣ " ;

51      std::cout << sig .GetEntropy() << std::endl;

52      std::cout << " Original␣dim␣ value ␣ = ␣ " ;

53      std::cout << sig .GetDim() << std::endl; 54

55      Signal sig2 = sig .Downsample ();

56      std::cout << "Downsampled␣dim␣ value ␣ = ␣ " ;

57      std::cout << sig2 .GetDim() << std::endl;

58      std::cout << "Downsampled␣entropy␣ value ␣ = ␣ " ;

59      std::cout << sig2 .GetEntropy() << std::endl; 60

61      Signal sig3 = sig .DownsampleMean ();

62      std::cout << "Mean␣downsampled␣dim␣ value ␣ = ␣ " ;

63      std::cout << sig3 .GetDim() << std::endl;

64      std::cout << "Mean␣downsampled␣entropy␣ value ␣ = ␣ " ;

65      std::cout << sig3 .GetEntropy() << std::endl;

66

67      return 0; 68   }

(a) The code assumes that the member function GetDim() exists, but this is currently missing. The purpose of this function is to return the number of samples in the signal (i.e. the number of elements in the variable _data). Write code to implement this function, and state where it should be placed to form part of the Signal class.

(b) The code assumes that the member function GetIntensityRange() ex-

ists (see line 19), whose purpose is to extract the minimum and maximum values in the signal, but this is currently missing. Write this function for the Signal class.

(c) The GetEntropy()  member-function of the Signal class is incomplete (from line 30).  Finalise it to return the signal’s Shannon entropy.  En- sure that your code accounts for the potential presence of a probability of zero.

(d) Only the simple downsampling approach has been implemented. Add the corresponding DownsampleMean() member function for the Signal class

to implement the aforementioned second strategy relying on a 3-point- neighborhood.

(e) The class is missing functionality to get values at a given index. The stu- dent decides to use operator overloading to implement the square bracket operator, to make it possible to write constructs such as signal[n] to re-

trieve the nth  signal value.  Add the operator[] overload to implement this functionality.

Question B.2

A research team is developing a cheap wearable device to monitor cardiac function. This device measures a single electrocardiogram (ECG) signal con- tinuously at a fixed sample rate of 100Hz, and aims to perform real-time anal- ysis of the signal for early detection of problems. As part of their risk assess- ment, they identify two possible failure modes:

1.  Loss of contact with the electrode. In this case, there is no effective mon- itoring, and there is a risk of problems going undetected. If this happens, the device needs to raise an alarm so the electrode can be correctly re-positioned.

2.  Failure of the algorithms used in the analysis.  These involve complex methods that are still under development, and could crash or hang for a variety of reasons, such as coding errors or unforeseen flaws in the algorithms used. In this case, there would be no warning issued in case of serious problems, such as cardiac arrest.  As a fail-safe, the device could perform a much simpler analysis in parallel and raise an alarm if this detects any obvious abnormalities.

To guard against these failures, they decide to set up a simple independent monitoring program to run in parallel with the main analysis.  Its function is purely to inspect the signal and verify that the expected level of variation is observed over a reasonable time window.

They write a small C++ program to monitor the signal, shown below.  The program reads a batch of sequential measurements from its standard in- put (std::cin), then computes the range between the maximum and min- imum values observed, and issues a warning on its standard error stream

(std::cerr) if the range falls below the specified threshold.

monitor .h:

1   # include   < iostream >

2   # include   <fstream >

3   # include   < vector >

4

5

6    class   Monitor 7   {

8            public :

9                     Monitor   ( int   batch _ size   =   1024)   :

10                              _ size   (batch _ size)  {

11                                       _batch = new int  [ _size];

12                              }

13

14                     bool get_next_batch  () {

15                              for ( int n = 0; n < _size; ++n) {

16                                       std::cin >> _batch[n];

17                                       if (!std::cin)

18                                                return false ; 19                              }

20                              return true ;

21                     }

22

23            private :

24                     int _size;

25                     int * _batch; 26   };

main .cpp:

1   # include "monitor .h "

2

3   using namespace std; 4

5    int main  () 6   {

7             const int threshold = 100; 8

9            Monitor monitor;

10            while (monitor .get_next_batch ()) {

11                     int min = monitor .get_value (0);

12                     int max = min;

13                     for ( int n = 1; n < monitor .get_batch_size (); n++) {

14                              if (monitor .get_value(n) < min)

15                                       min = monitor .get_value(n);

16                              if (monitor .get_value(n) > max)

17                                       max = monitor .get_value(n);

18                     }

19                     if ((max -min) < threshold)

20                              cerr << "WARNING : ␣signal␣variation␣too␣low " << endl; 21            }

22

23            return 0; 24   }

In each of the following questions, you do not need to write out the whole updated program.   You only need to write down each change required and

state exactly where it would take place in the program. Make sure to take all your previous changes into account.

(a) The program will currently not compile as the get_batch_size() and

get_value() methods are missing. Add these to the relevant part of the program.

The get_batch_size() method should return the number of measure- ments in the batch that the program read from standard input, and the get_value() method should return the ith  value in the batch, where i is passed as an argument to the method.

(b) The program is currently at risk of memory leaks as memory is allocated

but never freed.  Add a destructor to the Monitor class to address this concern.

(c) The code has been reviewed by other developers on the team, and they recommend the use of the standard library’s std::vector class to hold the batch of data, rather than relying on manual memory management. Modify the code accordingly.

(d) Another recommendation from the code review is to add a method to the Monitor class to compute the range within the batch, to simplify the code in the main() function and make it more readable. Modify the code accordingly.

Question B.3

Electro-anatomical (EAM) systems are routinely used for the guidance of catheter-based ablation of cardiac arrhythmias. These systems are connected to one or several catheters which are used to map and/or ablate heart tis- sues.  EAM systems enable real-time 3D visualisation of the catheters loca- tions, heart anatomy and tissue electrical properties. In this design, standard catheters can be defined by their number of electrodes and capability to mea- sure contact force (yes or no).  A more specific kind of catheter has been recently developed to perform such procedures in an MRI scanner.   Such MRI-compatible catheters have the same properties as standard catheters but are also defined by their number of integrated micro-coils which are used for active tracking (i.e. real-time localisation of the catheter). MR-compatible catheters can only have one of the following configurations: none, one, or two active tracking coils.

(a)  Produce a UML class diagram to represent an EAM system.  It should be possible to display the characteristics of the system: number of con- nected catheters and their corresponding properties. The design should allow the catheters to be simultaneously connected to other guidance systems in the future. You should use information hiding when defining your classes, but you don’t need to include inspector/mutator functions for any attributes. You also don’t need to provide any constructors in your design.

(b) Write all c++ code required to implement your design. You can assume that all class definitions will be in the same source file.

Question B.4

For their research, a group of students is required to develop a database to store information about patients.  This information includes demographic in- formation about the patient (year of birth, gender, height, weight), as well as some imaging information in the form of Computer Tomography (CT), Mag- netic Resonance Imaging (MRI) and Ultra-sound (US) scans.  Each scan is completed by a radiological read (analysis from a radiologist). It also includes some clinical information such as medication and disease history.   Lastly, some genetic information about the patient will also need to be stored. Each patient can have several investigations of each type: imaging, clinical, genetic information. Another requirement is that the database can be stored and re- trieved from disk.

They decide to set up their database as a list of patients and produce the following UML diagram for their design:

 

The students need to write a small program that prints out the PatientID of each male individual who underwent an MRI scan when aged between 50 and

70 years old and who also has genetic information available in the database. They start writing the code below to match the UML design.

In the code, GenderType is an enum that can take the values Male or Female. Likewise, ImagingModality is an enum that can take the values MRI, CT and

US.

1   # include   <string >

2   # include   < iostream >

3   # include   " Database . h "

4

5    int  main()

6   {

7        //   Load   the   existing   database   from   disk

8        Database   db;

9        db . load( " database . db " );

10

11        for   ( unsigned   int   i=0;   db . GetNumberOfPatients ();   ++i) 12        {

13            //   Complete   the   code

14        }

15        return   0; 16   }

(a) Complete their initial code of the main function (assuming all classes of

the above UML diagram have been implemented) to help them retrieve the required information.

(b) The students need to modify the program written in (a) so that they can specify the target age range, gender and modality at runtime (which were hard-coded in (a) to 50-70 years old, Male, and MRI, respectively), either via the command-line or typed in from standard input. Modify your initial code to implement this functionality (you only need to implement one of the two options between command-line and typed in from standard input).