FII: Object Oriented Programming (OOP) Course

  • Course description form: RO EN

General Objectives

Assimilation of object-oriented programming at the abstract level (concepts related to classes and design patterns), and at the concrete level using the C ++ programming language.

Specific Objectives

Ability to understand, explain, analyze, and use:

  1. classes, objects, class hierarchies, polymorphism, abstract classes, interfaces, parameterized classes;
  2. modeling in UML at an introductory level;
  3. C ++ language (ISO Standard), with emphasis on the representation of classes, objects, and relationships between them;
  4. design patterns;
  5. Standard Generic Type Library (STL).

Schedule

You can find the schedule for this course:

Grading and minimal requirements

Assessment

  • First lab evaluation (week 8) --> 30 points (30%)
  • Second lab evaluation (week 14 or 15) --> 30 points (30%)
  • Final evaluation (examination period) --> 30 points (30%)
  • Lab activity --> up to 1 point for each laboratory and no more than 10 points in total (10%)

The contents of the tests will be oriented towards verifying the level of understanding of the concepts, results, and way of thinking presented at the course and at the laboratories. Therefore, the answers must be based on these elements, the alternative solutions being considered only if they are correlated/compared with those taught in the course/laboratories or if they are part of the recommended additional bibliography, in which case it must be mentioned. The role of the tests is to verify the level of mastery, understanding, and use of the concepts taught in the course. The definitions and notations taught in the course will be used in the formulation of the solutions.

Minimal performance standards

Passing is conditioned on gaining a minimum of 45 points and should reflect the assimilation of the following concepts & skills:

  • the capability to write C++ programs based on specifications
  • the capability to correctly apply OOP principles (inheritance, polymorphism, etc)
  • the ability to understand OO principles/programming-techniques written in C++
  • the ability to detect simple errors in a C++ program and understand them

Grades

They are established according to the distribution of the scores of those promoted: the sum of the scores obtained at the laboratories and the ones from the tests. The percentages proposed by ECTS ("top 10%, next 25%, next 30%, next 25%, lowest 10%") correspond to the normal distribution and are indicative. Their application will be made with possible changes, depending on the actual distribution of scores.

For this reason, the ECTS percentages are only supported as a starting point in establishing the final grades; if the distribution of scores is different than the normal one, the percentages will be adjusted accordingly.

For students from past years

Previous results obtained on past OOP courses/labs will NOT be equated. You will need to take both the lab and course tests to pass the OOP exam.

Conducting the courses and the labs

Both Courses and Lab will be held on-site. For asynchronous communication, the discipline's Discord Server will be used.

Courses schedule

CourseLuniMartiMiercuri
1C112C112C2
2OnLine (Zoom)OnLine (Zoom)OnLine (Zoom)
3C112C112C2
4C112C112C2
5C112C112C2
6TBDOnLine (Zoom)C2
7C112C112C2

Courses

  1. Introduction

    • Administrative
    • Glossary
    • Compilers
    • OS architecture
    • C++ history and revisions
    • From C to C++
    • Classes (Data Members & methods)
    • Link: Course 1
  2. C++ Language specifiers

    • Pointers and References
    • Method overloading
    • NULL pointer
    • "const" specifier
    • "friend" specifier
    • Link: Course 2
  3. Creating an object

    • Initialization lists (recap)
    • Constructors
    • Const & Reference data members
    • Delegating constructor
    • Initialization lists for classes
    • Value Types
    • Copy & Move Constructors
    • Constraints
    • Link: Course 3
  4. Operators

    • Destructor
    • C++ operators
    • Operators for classes
    • Operations with objects
    • Link: Course 4
  5. Inheritance

    • Inheritance concepts
    • Virtual methods
    • How virtual methods are modeled by the C++ compiler
    • Covariance
    • Abstract classes (Interfaces)
    • Memory alignment in case of inheritance
    • Link: Course 5
  6. Templates

    • Casts
    • Macros
    • Macros vs Inline
    • Literals
    • Templates
    • Function templates
    • Class templates
    • Template specialization
    • Compile-time assertion checking
    • Link: Course 6
  7. STL (1)

    • Sequence containers
    • Adaptors
    • I/O Streams
    • Strings
    • Initialization lists
    • Link: Course 7

Labs

Lab 1

Learn how to use GIT

Learn simple command:

Each student will create his/hers private GITHUB repository where his/her teaching assistant will be set as a collaborator for that repo. All of the operations from now on (lab exams, lab homework will be done via that repo (or multiple repos) ).

1. Recap simple C library functions

Write a program in C-Language that open the file "in.txt", and prints the sum of the numbers that are found on each line of the file "in.txt". To open the file use fopen API. Write your own function that converts a string to a number (similar cu atoi API). To print something to the screen, use the printf API.

Example: let's consider the following "ini.txt" file:

123
198698
5009
983279

The program will print to the screen 1187109.

2. Recap scanf/printf

Read a sentence from the input using scanf API. Then sort split it into words and write to the screen (using the printf API) the words sorted (from the longest one to the shortest one).If two words have the same length - they will be sorted out alphabetically. We consider that each word is separated from another one using space (one or multiple).

Example: let's consider the following sentence: `"I went to the library yesterday"``. The program will print the following to the screen:

yesterday
library
went
the
to
I

3. Some C and C++ problem

Lets consider the following code:

#include <iostream>
using namespace std;

bool isPrime(int n)
{
    for (int tr = 2; tr < n / ......; tr++)
        if ((n % ...... ) == 0)
            return ......;
    return true;
}
int main()
{
    int n;
    std::cout << "Enter a number:";
    std::cin >> ......;
    if (isPrime(n))
        std::cout << n << " is prime !";
    else 
        std::cout << n << " is NOT prime !";
    return 0;
}

Fill in the missing code (dots: ...... ) to make this program work as expected.

Lab 1 Extra

Find and solve all the mistakes in the following code.

header.h

#pragma once

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>

#define MAX 1000

enum VALORI {
	INMULTIRE = 0,
	SUMA,
	REZERVAT1,
	DIFERENTA,
	REZERVAT2,
	IMPARTIRE
};

typedef int (*func)(int, int);

struct Content {
	int p1;
	int p2;
};

int Sum(int a, int b);
int Dif(int a, int b);
int Mul(int a, int b);
int Div(int a, int b);


source.cpp

#include "header.h"

int Sum(int a, float b) { return a - b; }
int Dif(char a, int b) { return a / b; }
int Mul(long a, int b) { return a + b; }
char Div(int a, int b) { return a * b; }

int main(int argc, char* argv[])
{
	char input[7] = "---H***E+++L+++L///O---P+++O/+-**O---";
	func Operatori[4] = {Sum, Dif, 65, Mul, 0, Div};
	int S, V;
	Content x = 15;
	double idx;

	for (i = 0; i < strlen(input); i++)
	{
		switch (input[i] - 42)
		{
			case INMULTIRE:
				idx = 2;
				x.p1 = 3;
				x.p2 = 3;
			case SUMA:
				idx = 0;
				x.p1 = 7;
				x.p2 = 5;
			case DIFERENTA:
				idx = 1;
				x.p1 = 10;
				x.p2 = 1;
			case IMPARTIRE:
				idx = 3;
				x.p1 = 8;
				x.p2 = 4;
		}

		S = S + Operatori[idx](x.p1, x.p2);
	}

	//S=337
	printf("S = %c\n", S);

	return 0;
}

Lab 2

  1. Write a class in C++ that has the following definition:
class NumberList
{
    int numbers[10];
    int count;
public:
    void Init();          // count will be 0
    bool Add(int x);      // adds X to the numbers list and increase the data member count.
                          // if count is bigger or equal to 10, the function will return false
    void Sort();          // will sort the numbers vector
    void Print();         // will print the current vector
}

Organize the code in the following way:

  • a header file called NumberList.h
  • a cpp file called NumberList.cpp that contains the source code for class NumberList
  • a main file called main.cpp that contains the main function and has an example on how to use NumberList. The example must include using all methods from the class. make sure that precompile headers are NOT used (for Visual Studio setup).
  1. Design a C++ class (following the previous problem) that reflects the properties of a student. The class should include the following:
  • methods to set and get the name of the student
  • methods to set and get the grade for mathematics (a grade must be a float value from 1 to 10)
  • methods to set and get the grade for English (a grade must be a float value from 1 to 10)
  • methods to set and get the grade for History (a grade must be a float value from 1 to 10)
  • a method that retrieves the average grade
  • 5 global functions that compares two students in terms of name, grades, average. If two students are equal the return value of such a function will be 0. If the first student is bigger than the second one, the return value will be 1, otherwise -1.

Make sure that you have the following:

  • a header file for the class
  • a cpp file for the methods specific to the class
  • a header file for the global functions
  • a cpp file for the global functions implementation
  • a main.cpp file that shows how the methods and global functions can be used.

Lab 2 Extra

Design a C++ class named Movie that reflects the properties of a movie. The class should include the following:

  • methods to set and get the name of the movie (max 256 characters);
  • methods to set and get the release year;
  • methods to set and get the IMDB score (a double with values between 1 and 10);
  • methods to set and get the length of a movie, in minutes;
  • a method to get the number of passed years since the release (calculated at every call);
  • 5 global functions that compare two movies in terms of name, released year, IMDB score, length, and passed years.

The last functions will return an int with the values:

  • -1 if first < second;
  • 0 if first == second;
  • 1 if first > second;

Design a second class named MovieSeries that is able to hold at most 16 movies as pointers. The class will have methods for:

  • initialization (setting the count to 0);
  • adding a Movie as a pointer;
  • printing the information about the movies, each on a line;
  • sorting the movies descending after the number of passed years since the release;

Make sure that you have the following for each class:

  • header (.h) file for the class declaration;
  • source (.cpp) file for the methods specific to the class;
  • the variables should be private and the functions public;
  • a header file for the global functions declaration;
  • a cpp file for the global functions implementation;
  • a main file called main.cpp that contains the main function with the code from below;

The following main function should compile and work:

int main() {
    Movie ep5;
    ep5.set_name("Star Wars: Episode V - The Empire Strikes Back");
    ep5.set_score(8.7);
    ep5.set_year(1980);
    ep5.set_length(124);

    Movie ep4;
    ep4.set_name("Star Wars: Episode IV - A New Hope");
    ep4.set_score(8.6);
    ep4.set_year(1977);
    ep4.set_length(121);

    Movie ep6;
    ep6.set_name("Star Wars: Episode VI - Return of the Jedi");
    ep6.set_score(8.3);
    ep6.set_year(1983);
    ep6.set_length(131);

    printf(
          R"(
ep4, ep5 comparisons:
name        : %d
year        : %d
score       : %d
length      : %d
passed years: %d
)",
          movie_compare_name(ep4, ep5),
          movie_compare_year(ep4, ep5),
          movie_compare_score(ep4, ep5),
          movie_compare_length(ep4, ep5),
          movie_compare_passed_years(ep4, ep5));

    MovieSeries series;
    series.init();
    series.add(&ep5);
    series.add(&ep4);
    series.add(&ep6);

    series.sort();
    series.print();
}

Lab 3

  1. Write a class in C++ that has the following definition:
class Math
{
public:
    static int Add(int,int);
    static int Add(int,int,int);
    static int Add(double,double);
    static int Add(double,double,double);
    static int Mul(int,int);
    static int Mul(int,int,int);
    static int Mul(double,double);
    static int Mul(double,double,double);
    static int Add(int count,...); // sums up a list of integers
    static char* Add(const char *, const char *);
};

Organize the code in the following way:

  • a header file called Math.h
  • a cpp file called Math.cpp that contains the source code for class Math
  • a main file called main.cpp that contains the main function and has an example on how to use Math. The example must include using all methods from the class.
  • for the variadic method use pointers or va_start / va_end macros.
  • Add(const char *, const char *) will allocate memory that can add the two existing string. If one of the strings is nullptr, this function will return nullptr;
  1. Write a class in C++ that has the following definition:
class Canvas
{
    // add private data members
public:
    Canvas(int width,int height);
    void DrawCircle(int x, int y, int ray, char ch);
    void FillCircle(int x, int y, int ray, char ch);
    void DrawRect(int left, int top, int right, int bottom, char ch);
    void FillRect(int left, int top, int right, int bottom, char ch);
    void SetPoint(int x, int y, char ch);
    void DrawLine(int x1, int y1, int x2, int y2, char ch);
    void Print(); // shows what was printed
    void Clear(); // clears the canvas
};

Organize the code in the following way:

  • a header file called Canvas.h
  • a cpp file called Canvas.cpp that contains the source code for class Canvas
  • a main file called main.cpp that contains the main function and has an example on how to use Canvas. The example must include using all methods from the class.
  • use a matrix of type char for the canvas. A pixel is a cell in the matrix. A pixel is considered empty if it contains the space (value 32) character.
  • for the DrawLine algorithm use Braseham algorithm.

Lab 3 Extra

  1. Write a class in C++ that has the following definition:
class Math
{
public:
    static int Add(int,int);
    static int Add(int,int,int);
    static int Add(double,double);
    static int Add(double,double,double);
    static int Mul(int,int);
    static int Mul(int,int,int);
    static int Mul(double,double);
    static int Mul(double,double,double);
    static int Add(int count,...); // sums up a list of integers
    static char* Add(const char *, const char *);
};

Organize the code in the following way:

  • a header file called Math.h
  • a cpp file called Math.cpp that contains the source code for class Math
  • a main file called main.cpp that contains the main function and has an example on how to use Math. The example must include using all methods from the class.
  • for the variadic method use pointers or va_start / va_end macros.
  • Add(const char *, const char *) will allocate memory that can add the two existing string. If one of the strings is nullptr, this function will return nullptr;
  1. Implement the methods of the class so the following code works:

canvas.h

class Canvas {
  public:
    // contructor will call the clear method
    Canvas(int lines, int columns);

    // set the character at the position x and y to value
    void set_pixel(int x, int y, char value);
    
    // tuples of x, y, value
    void set_pixels(int count, ...);

    void clear();
    void print() const;
};

main.cpp

int main() {
    Canvas canvas(10, 50);
    canvas.set_pixels(4, 4, 25, 124, 3, 33, 124, 2, 24, 95, 4, 3, 95);
    canvas.set_pixels(3, 7, 2, 95, 4, 21, 124, 5, 16, 95);
    canvas.set_pixels(3, 4, 41, 124, 7, 1, 124, 5, 8, 92);
    canvas.set_pixels(3, 1, 31, 40, 2, 3, 95, 2, 41, 124);
    canvas.set_pixels(5, 2, 16, 95, 5, 35, 92, 6, 3, 95, 2, 11, 95, 5, 3, 95);
    canvas.set_pixels(5, 2, 38, 95, 4, 9, 40, 3, 41, 124, 2, 37, 95, 2, 25, 124);
    canvas.set_pixels(5, 5, 27, 124, 2, 27, 124, 4, 0, 124, 3, 35, 47, 2, 18, 95);
    canvas.set_pixels(4, 4, 13, 124, 4, 37, 95, 4, 16, 40, 3, 6, 124);
    canvas.set_pixels(4, 7, 32, 47, 4, 20, 124, 5, 11, 95, 5, 42, 95);
    canvas.set_pixels(4, 5, 15, 92, 4, 34, 124, 4, 45, 41, 5, 24, 95);
    canvas.set_pixels(3, 4, 2, 40, 7, 3, 95, 2, 44, 95);
    canvas.set_pixels(5, 6, 30, 95, 5, 45, 95, 4, 31, 124, 4, 7, 124, 3, 43, 39);
    canvas.set_pixels(3, 5, 17, 95, 1, 27, 124, 2, 5, 95);
    canvas.set_pixels(5, 3, 44, 95, 3, 19, 92, 5, 23, 95, 3, 8, 47, 2, 10, 95);
    canvas.set_pixels(4, 6, 6, 124, 5, 19, 47, 3, 24, 95, 3, 27, 124);
    canvas.set_pixels(5, 3, 10, 95, 4, 44, 95, 2, 9, 95, 0, 32, 95, 5, 2, 95);
    canvas.set_pixels(4, 6, 2, 95, 7, 31, 95, 1, 25, 124, 2, 36, 95);
    canvas.set_pixels(5, 3, 46, 92, 5, 25, 44, 1, 43, 124, 5, 46, 47, 3, 15, 47);
    canvas.set_pixels(3, 4, 17, 95, 2, 23, 95, 3, 39, 92);
    canvas.set_pixels(3, 4, 47, 124, 2, 45, 95, 3, 37, 95);
    canvas.set_pixels(5, 5, 44, 95, 2, 2, 95, 5, 10, 95, 5, 9, 95, 4, 43, 124);
    canvas.set_pixels(3, 4, 38, 41, 2, 17, 95, 0, 26, 95);
    canvas.set_pixels(4, 4, 18, 41, 7, 5, 47, 5, 41, 124, 5, 33, 124);
    canvas.set_pixels(4, 5, 12, 47, 5, 22, 92, 6, 33, 124, 5, 31, 124);
    canvas.set_pixels(5, 4, 40, 124, 3, 3, 95, 4, 4, 124, 6, 31, 47, 3, 4, 96);
    canvas.set_pixels(3, 0, 42, 95, 5, 18, 95, 4, 27, 124);
    canvas.set_pixels(5, 3, 12, 92, 2, 32, 95, 5, 37, 95, 5, 26, 95, 5, 39, 47);
    canvas.set_pixels(4, 3, 25, 96, 4, 14, 124, 4, 33, 124, 3, 1, 47);
    canvas.set_pixels(5, 5, 36, 95, 7, 30, 95, 6, 4, 47, 4, 24, 95, 1, 32, 95);
    canvas.set_pixels(3, 3, 22, 47, 4, 23, 40, 5, 6, 124);
    canvas.set_pixels(3, 1, 33, 41, 1, 41, 124, 7, 29, 124);
    canvas.set_pixels(4, 4, 6, 124, 5, 38, 95, 3, 31, 124, 7, 4, 95);
    canvas.set_pixels(3, 4, 11, 41, 4, 10, 95, 5, 1, 92);
    canvas.set_pixels(4, 2, 43, 124, 3, 17, 95, 5, 4, 44, 4, 36, 40);
    canvas.set_pixels(1, 5, 43, 46);

    canvas.print();
}

Lab 4

  1. Write a class in C++ that has the following definition:
class Sort
{
    // add data members
public:
    // add constuctors
    void InsertSort(bool ascendent=false);
    void QuickSort(bool ascendent=false);
    void BubbleSort(bool ascendent=false);
    void Print();
    int  GetElementsCount();
    int  GetElementFromIndex(int index);
};

Organize the code in the following way:

  • a header file called Sort.h
  • a .cpp file called Sort.cpp that contains the source code for class Sort
  • a main file called main.cpp that contains the main function and has an example on how to use Sort. The example must include using all methods from the class.

Add several constructors that will allow the following:

  • create the list that needs to be sorted out of random values within a specific interval (min, max). The constructor will receive 3 parameters (the number of elements in the list, minimum value, maximum value).
  • create the list that needs to be sorted from an initialization list
  • create the list that needs to be sorted from an existing vector (the constructor will have two parameters - one being the vector, the other one being the number of elements from the vector)
  • create the list that needs to be sorted using variadic parameters (use va_args for this)
  • create the list that needs to be sorted from a string (e.g. "10,40,100,5,70" -> each number is separated from the rest of the number with a comma). It is assumed that the string is correctly written (no space, only numerical characters and commas)

OBS: By list in this context we refer to a vector or any form of container that stores elements (it could be a double-linked-list, a heap vector or an array).

Lab 5

  1. Write a class in C++ that has the following definition:
class Number
{
   // add data members
public:
   Number(const char * value, int base); // where base is between 2 and 16
   ~Number();

   // add operators and copy/move constructor

   void SwitchBase(int newBase);
   void Print();
   int  GetDigitsCount(); // returns the number of digits for the current number
   int  GetBase(); // returns the current base
}

Organize the code in the following way:

  • a header file called Number.h
  • a cpp file called Number.cpp that contains the source code for class Number
  • a main file called main.cpp that contains the main function and has an example on how to use Number. The example must include using all methods from the class.
  • add the following operators: addition, subtraction, index operator, relation operators (> , < , >= , <=, ==, etc)
  • add copy & move constructors and move assignment operator
  • when performing operations with two Number object that have a different base, the result (except for the relation and index operators) will have the biggest base of the two Number instances.
  • for addition and subtraction use friend functions
  • implement the -- operator with the following syntax: if used in a prefix form it will remove the first (most significant digit) from the number; if used in a post-fix form it will remove the last (least significant) digit from the number;

Example

int main()
{
   Number n1("10110010",2);
   Number n2("734",8);
   Number n3("FF",16);

   printf("n1 has %d digits and it is written in base %d\n",n1.GetDigitsCount(),n1.GetBase());
   for (int tr=0;tr<n1.GetDigitsCount();tr++)
   {
      printf("n1[%d]=%c\n",tr,n1[tr]);
   }
   n1.Print();
   n2.Print();
   n1 = (n2+n3-n1)+n1; // after this n1 will be in base 16
   n1.SwitchBase(2);
   n1.Print();

   if (n1>n2) printf("n1 is bigger than n2\n"); else printf("n2 is bigger than n1\n");

   Number n4=12345; // n4 will be in base 10
   n1 = 255; // n1 will be 11111111 (value 255 from base 10 in base 2)
   n4 += n1; 
   n4.Print();

   n4 = "13579"; // n4 mentains its base (10) and will be 13579
   n4.Print();
   --n4; // the first digit from n4 will be remove ==> n4 becomes 3579
   n4.Print();
   n4--; // the last digit from n4 will be remove ==> n4 becomes 357
   n4.Print();

   return 0;
}

Lab 5 Extra

Write a class Complex with the following declaration and part implementation.

The class will implement the following operators:

  1. op+, op-, op*

These will accept 2 complex number, a complex number and a real number, or a real number and a complex number. (9 in total)

  1. op- unary
  2. op== si op!=
  3. op<< stream operators for printing
  4. op++ prefixed and postfixed and op-- prefixed and postfixed
  5. op() with the below semantics total: 18 operators

op++ postfixed MUST use op++ prefixed

op-- postfixed MUST use op-- prefixed

#pragma once

#include <ostream>

class Complex {
  private:
    double real_data;
    double imag_data;

  public:
    Complex();
    Complex(double real, double imag);

    bool is_real() const;

    double real() const;
    double imag() const;
    double abs() const;
    Complex conjugate() const;

    Complex& operator()(double real, double imag);
};

Complex operator+(const Complex& l, const Complex& r);
Complex operator+(const Complex& l, double r);
Complex operator+(double l, const Complex& r);

Complex operator-(const Complex& obj);

bool operator==(const Complex& l, const Complex& r);

std::ostream& operator<<(std::ostream& out, const Complex& complex);
#include "complex.h"

Complex::Complex() : Complex(0, 0) {
}

Complex::Complex(double real, double imag) {
    real_data = real;
    imag_data = imag;
}

bool Complex::is_real() const {
    return imag() == 0;
}

double Complex::real() const {
    return real_data;
}

double Complex::imag() const {
    return imag_data;
}

double Complex::abs() const {
    return sqrt(real() * real() + imag() * imag());
}

Complex Complex::conjugate() const {
    return { real(), -imag() };
}

The follosing main.cpp file must compile and work at runtime.

#include <iostream>p

#include <cmath>
#include "complex.h"

bool double_equals(double l, double r) {
    return abs(l - r) < 0.001;
}

#define check(x)                                                                                                       \
    if (!(x)) {                                                                                                        \
        printf("at line #%d -> `%s` is not satisfied\n", __LINE__, #x);                                                \
        return 1;                                                                                                      \
    }

int main() {
    Complex a{ 1, 2 };
    check(double_equals(a.real(), 1));
    check(double_equals(a.imag(), 2));

    Complex b{ 2, 3 };
    Complex c = a + b;
    check(double_equals(c.real(), 3));
    check(double_equals(c.imag(), 5));

    Complex d = c - a;
    check(b == d);

    Complex e = (a * d).conjugate();
    check(double_equals(e.imag(), -7));

    {
        // increment the real part
        Complex res1 = e++;
        check(res1 == e - 1);
        Complex& res2 = ++e;
        check(res2 == e);
        check(double_equals(e.real(), -2));
    }

    {
        // decrement the real part
        Complex res1 = e--;
        check(res1 == e + 1);
        Complex& res2 = --e;
        check(res2 == e);
        check(double_equals(e.real(), -4));
    }

    Complex f = (a + b - d) * c;
    if (f != Complex{ 1, 2 }) {
        // prints in the format a +/i bi
        // if a or b are not 0, they won't be printed
        // if they're both 0, 0 will be printed
        // examples:                 5 + 4i
        //                          -3 - 2i
        //                          -6
        //                           5i
        std::cout << f << '\n' << a << '\n';
        std::cout << Complex{ 1, 2 } << '\n'
                  << Complex{ 1, -2 } << '\n'
                  << Complex{ 0, 5 } << '\n'
                  << Complex{ 7, 0 } << '\n'
                  << Complex{ 0, 0 } << '\n';
    }

    // op() will update the real part and the imaginary part
    // it will behave as a setter for both
    Complex g = f(-1, -2)(-2, -3)(-4, -5);
    Complex h = { -4, -5 };
    check(g == h);

    Complex i = h - (h + 5) * 2;
    check(double_equals(i.real(), -6));

    // unary op-
    Complex j = -i + i;
    check(double_equals(j.abs(), 0));
}

Lab 6

  1. Write the following classes in C++:
  • An abstract class Car that reflects some properties on a car (fuel capacity, fuel consumption, average speed on different conditions (Rain, Sunny, Snow)).
  • Derive from this class several type of Cars with different characteristics for fuel capacity, fuel consumption, etc.
  • For weather condition create an enum object.
  • Create a class circuit that will test how different cars behave in a race depending on the length of the circuit and the race weather condition. The circuit will use polymorphism to simulate the race conditions (e.g. will have an array of objects of type Car*).

Use the following main snippet to show how this ensemble works:

int main()
{
   Circuit c;
   c.SetLength(100);
   c.SetWeather(Weather::Rain);
   c.AddCar(new Volvo());
   c.AddCar(new BMW());
   c.AddCar(new Seat());
   c.AddCar(new Fiat());
   c.AddCar(new RangeRover());
   c.Race();
   c.ShowFinalRanks(); // it will print the time each car needed to finish the circuit sorted from the fastest car to the slowest.
   c.ShowWhoDidNotFinish(); // it is possible that some cars don't have enough fuel to finish the circuit
   return 0;
}

Organize the code in the following way:

  • a header file for each different car (Volvo, BMW, ...), a header file for the abstract class Car, a header file for the Weather enum and one for Circuit.
  • a .cpp file for each different implementation of a car (Volvo, BMW, etc.). Abstract class Car only has virtual methods (it does not need a .cpp file).
  • a .cpp file for Circuit class.
  • a main file called main.cpp that contains the main function.

Lab 6

Implement the following classes that represents json objects:

  • base class JsonValue with an abstract destructor and an abstract print function that takes an ostream&
  • NullValue: represents a null
  • NumberValue: stores a number
  • BoolValue: stores a bool
  • StringValue: stores a string (max size 255)
  • ArrayValue: stores an array of values (max 16); the add function will take a value pointer and add it to the array
  • ObjectValue: stores an array of pairs of (name, value) (max 16); the add function will take a string for name and a pointer for the value and add it.

Also add a cast operator to unsigned that returns the number of nodes.

You may have all the class declarations in a single header, and all the definitions in a cpp.

The print function will print the tree in such a way that the output is valid json.

Bonus 1: make the print function constant. Bonus 2: make sure there are no memory leaks. Bonus 3: add a command line argument that says whether the output should go to stdout or to a file, and which file. Bonus 4: make the print function print with proper indentation with the help of a new argument.

The base class will look like this:

class JsonValue {
public:
    virtual ~JsonValue() = 0;

    virtual void print(std::ostream& out) = 0;
};

Take the following code:

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

int main() {
    auto array_numbers = new ArrayValue();
    array_numbers->add(new NumberValue(5));
    array_numbers->add(new NumberValue(10));
    array_numbers->add(new NumberValue(15));

    auto array_strings = new ArrayValue();
    array_strings->add(new StringValue("abc"));
    array_strings->add(new StringValue("def"));
    array_strings->add(new StringValue("ghi"));

    auto subobject = new ObjectValue();
    subobject->add("email", new StringValue("t@gmail.com"));
    subobject->add("name", new StringValue("T"));
    subobject->add("online", new BoolValue(true));

    auto object = new ObjectValue();
    object->add("n", new NullValue());
    object->add("array_numbers", array_numbers);
    object->add("array_strings", array_strings);
    object->add("info", subobject);

    std::cout << "Top node has " << (unsigned) *object << " subnodes\n";

    object->print(std::cout);
}

The last object->print(std::cout) should print something like:

{"n": null, "array_numbers": [5, 10, 15], "array_strings": ["abc", "def", "ghi"], "info": {"email": "t@gmail.com", "name": "T", "online": true}}

Check your output corectness here.

Lab 7

  1. Write two C++ literals for Kelvin and Fahrenheit conversions to Celsius so that the following code works.
int main() {
    float a = 300_Kelvin;
    float b = 120_Fahrenheit;
    return 0;
}

Organize the code in the following way:

  • a main file called main.cpp that contains the main function and has an example on how to use those two literals (similar to the explained in the previous main function)
  • Use the following link for explanation on how to convert from Kelvin and Fahrenheit to Celsius.
  1. Write a template that simulates a tree template. Each node in the tree will contain a value of type T (the template type) and a list of children. YOU ARE NOT ALLOWED TO USE ANY STL TEMPLATE TO STORE THE LIST OF CHILDREN.

Add the following methods:

  • add_node method (to add new node to the tree). The method will receive the parent node or nullptr (in the last case, the new node will be the root of the tree).
  • get_node method (returns a reference / method to a node). The method receives a pointer/reference to its parent (if the reference is nullptr, than the root node will be returned).
  • delete_node method (deletes a node and all its children)
  • find method --> recursively search all nodes for a parameter. The method will receive a pointer to a function that will compare the parameter received to the value T from each node. Thre method returns the first occurence.
  • insert method (insert an new node in a tree at a specific index, given its parent note.)
  • sort method (sort all children from a specific node ==> use a callback function to provide a way to compare two elements. If the callback function is not present (nullptr), operator< is used.)
  • count method (returns how many children a node has). This method walks recursively through all children. If call with nullptr, it returns the count of all children from the root of the tree

1. Write two C++ literals for Kelvin and Fahrenheit conversions to Celsius so that the following code works.

int main() {
    float a = 300_Kelvin;
    float b = 120_Fahrenheit;
    return 0;
}

2. Implement a class template for a Vector of elements that has the following methods:

  • insert(index, element): inserts the element at the specified index (must be between 0 and size)
  • remove(index): removes an element at the specified index
  • sort(cmp): sorts the vector by using a comparison function; add an overload that takes no parameters and uses operator< instead
  • print: prints the vector elements

The vector should also have a copy/move constructor, along with an operator[] defined, which returns the element at the given index. You MUST have the implementation in the header.

int compare_ints(int x, int y) {
    // return -1, x < y
    // return 1, x > y
    // return 0, x == y
}

int main() {
    Vector<int> v;

    // index, element
    v.insert(0, 10);
    v.insert(1, 5);
    v.insert(2, 20);

    Vector<int> w = v;

    // index
    v.remove(0);
    v.sort(compare_ints);
    printf("%d\n", w[0]);

    v.print();
}