FII: Object Oriented Programming (OOP) Course
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:
- classes, objects, class hierarchies, polymorphism, abstract classes, interfaces, parameterized classes;
- modeling in UML at an introductory level;
- C ++ language (ISO Standard), with emphasis on the representation of classes, objects, and relationships between them;
- design patterns;
- 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 than10
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
-
Introduction
- Administrative
- Glossary
- Compilers
- OS architecture
- C++ history and revisions
- From C to C++
- Classes (Data Members & methods)
- Link: Course 1
-
C++ Language specifiers
- Pointers and References
- Method overloading
- NULL pointer
- "const" specifier
- "friend" specifier
- Link: Course 2
-
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
-
Operators
- Destructor
- C++ operators
- Operators for classes
- Operations with objects
- Link: Course 4
-
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
-
Templates
- Casts
- Macros
- Macros vs Inline
- Literals
- Templates
- Function templates
- Class templates
- Template specialization
- Compile-time assertion checking
- Link: Course 6
-
STL
- Sequence containers
- Adaptors
- I/O Streams
- Strings
- Initialization lists
- Link: Course 7
-
STL (2)
- Associative containers
- Smart Pointers
- Link: Course 8
-
Advances beyond C+98
- Constant expressions
- For each (Range-based for loop)
- Type inference
- Structured binding (destructuring)
- Static Polymorphism (CRTP)
- Plain Old Data (POD)
- Link: Course 9
-
Lambda expressions
- Modeling lambda expression behavior
- Implicit conversion to a pointer to a function
- Lambdas and STL
- Using lambda with templates (Generic lambdas)
- Mutable capture
- Initialized lambda capture
- New features in C++17 and beyond
- Link: Course 10
-
Exceptions
- Basic Exceptions
- Starndard Exceptions
- noexcept keyword
- Modeling Exception Behavior
- SEH (Structured Exception Handling)
- RAII
- Link: Course 11
-
Design Patterns
- SOLID Principles
- Gang of Four (GoF)
- Singleton
- Multiton
- Factory
- Builder
- Adaptor
- Composite
- Visitor
- Observer
- Chain of Responsibility
- Link: Course 12
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
- 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).
- 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
- 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;
- 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
- 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;
- 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
- 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
- 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:
- 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)
- op- unary
- op== si op!=
- op<< stream operators for printing
- op++ prefixed and postfixed and op-- prefixed and postfixed
- 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
- 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 nullNumberValue
: stores a numberBoolValue
: stores a boolStringValue
: 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 arrayObjectValue
: 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
- 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.
- 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();
}
Lab 8
Write a program that does the following:
- Reads a phrase / sentence from a text file into a std::string object
- Split the phrase in words. Consider that the following characters are separators (space, comma, question and exclamation mark, point). Words may be separated by multiple spaces. Use only methods available in the
std::string
class for this task - Creates a
std::map
object that counts how many times each word is encountered. Don't take word casing into consideration (case-insensitive). - Use a
std::priority_queue
to sort each word using the number of times it was found. if two words have the same number of appearance in the phrase, they will be sorted lexicographically. - Print the words after they are sorted
Example:
Let's assume that we have a file that contains the following phrase: "I bought an apple. Then I eat an apple. Apple is my favorite."
- First we create a MAP with the following items:
{
"i" : 2,
"bought" : 1,
"an" : 2,
"apple" : 3,
"then" : 1,
"eat" : 1,
"is" : 1,
"my" : 1,
"favorite" : 1
}
- Then we sort these words based on the amount of time we found them and lexycographically
- Finally - we will print the following:
apple => 3
an => 2
i => 2
bought => 1
eat => 1
favorite => 1
is => 1
my => 1
then => 1
Lab 9
Write a C++ template Map that will make the following code :
int main()
{
Map<int, const char *> m;
m[10] = "C++";
m[20] = "test";
m[30] = "Poo";
for (auto[key, value, index] : m)
{
printf("Index:%d, Key=%d, Value=%s\n", index, key, value);
}
m[20] = "result";
for (auto[key, value, index] : m)
{
printf("Index:%d, Key=%d, Value=%s\n", index, key, value);
}
return 0;
}
will print the following on the screen:
Index:0, Key=10, Value=C++
Index:1, Key=20, Value=test
Index:2, Key=30, Value=Poo
Index:0, Key=10, Value=C++
Index:1, Key=20, Value=result
Index:2, Key=30, Value=Poo
For this task, use the following:
- structured binding
- auto keyword
- for-each
Besides this - add the following methods:
- a method Set that can be used to associate a value to a key
- a method Get using the following syntax
bool Get(const K& key, V& value)
that will copy the value associated to parameter key into the parameter value and returns true. If the parameter key does not exists in the map, Get method will return false - a method Count that returns the amount of elements in the map
- a method Clear that clears the entire map
- a method Delete that deletes a specific key (if exists) --> use the following syntax:
bool Delete(const K& key)
- a method Includes with the following syntax:
bool Includes(const Map<K,V>& map)
that checks if a map is included in another. A map A is included in another map B, if all keys from map A exists in map B
YOU ARE NOT ALLOWED TO USE STL TEMPLATES (Vector, Map, List, etc) for this problem.
Lab 10
Below you will see an example on how to use exceptions:
#include <iostream>
#include <exception>
using namespace std;
class exceptie1 : public exception
{
virtual const char* what() const throw()
{
return "Impartire la 0!";
}
};
class exceptie2 : public exception
{
virtual const char* what() const throw()
{
return "Indexul este inafara domeniului!";
}
};
int main()
{
int z=-1, x = 50, y = 0;
int arr[4] = { 0 };
int i = 10;
exceptie1 divide0;
exceptie2 index_out_of_bounds;
try
{
if (y==0)
throw divide0;
z = x / y;
cout << "Fara exceptie: z=" << z << endl;
}
catch (exception& e)
{
cout << "Exceptie: " << e.what() << endl;
}
try
{
if (i > 3)
throw index_out_of_bounds;
arr[i] = z;
for (i = 0; i < 4; i++)
cout << "arr[" << i << "] = " << arr[i] << endl;
}
catch (exception& e)
{
cout << "Exceptie: " << e.what() << endl;
}
return 0;
}
With this example in mind, build an array template (similar to the one below) and add exceptions to it.
class Compare
{
public:
virtual int CompareElements(void* e1, void* e2) = 0;
};
template<class T>
class ArrayIterator
{
private:
int Current; // mai adaugati si alte date si functii necesare pentru iterator
public:
ArrayIterator();
ArrayIterator& operator ++ ();
ArrayIterator& operator -- ();
bool operator= (ArrayIterator<T> &);
bool operator!=(ArrayIterator<T> &);
T* GetElement();
};
template<class T>
class Array
{
private:
T** List; // lista cu pointeri la obiecte de tipul T*
int Capacity; // dimensiunea listei de pointeri
int Size; // cate elemente sunt in lista
public:
Array(); // Lista nu e alocata, Capacity si Size = 0
~Array(); // destructor
Array(int capacity); // Lista e alocata cu 'capacity' elemente
Array(const Array<T> &otherArray); // constructor de copiere
T& operator[] (int index); // arunca exceptie daca index este out of range
const Array<T>& operator+=(const T &newElem); // adauga un element de tipul T la sfarsitul listei si returneaza this
const Array<T>& Insert(int index, const T &newElem); // adauga un element pe pozitia index, retureaza this. Daca index e invalid arunca o exceptie
const Array<T>& Insert(int index, const Array<T> otherArray); // adauga o lista pe pozitia index, retureaza this. Daca index e invalid arunca o exceptie
const Array<T>& Delete(int index); // sterge un element de pe pozitia index, returneaza this. Daca index e invalid arunca o exceptie
bool operator=(const Array<T> &otherArray);
void Sort(); // sorteaza folosind comparatia intre elementele din T
void Sort(int(*compare)(const T&, const T&)); // sorteaza folosind o functie de comparatie
void Sort(Compare *comparator); // sorteaza folosind un obiect de comparatie
// functii de cautare - returneaza pozitia elementului sau -1 daca nu exista
int BinarySearch(const T& elem); // cauta un element folosind binary search in Array
int BinarySearch(const T& elem, int(*compare)(const T&, const T&));// cauta un element folosind binary search si o functie de comparatie
int BinarySearch(const T& elem, Compare *comparator);// cauta un element folosind binary search si un comparator
int Find(const T& elem); // cauta un element in Array
int Find(const T& elem, int(*compare)(const T&, const T&));// cauta un element folosind o functie de comparatie
int Find(const T& elem, Compare *comparator);// cauta un element folosind un comparator
int GetSize();
int GetCapacity();
ArrayIterator<T> GetBeginIterator();
ArrayIterator<T> GetEndIterator();
};
Lab 11
In each group, pairs of 2 students will be formed. If the number of students is odd, there will also be a group of 3 students, with the rest being in pairs.
Within each group, the following tasks will be performed:
- Each student will write a template-based sorting algorithm that takes as a parameter a list of elements of the template type.
- Within this algorithm, 5 logic/functionality errors will be intentionally introduced.
- After completing this algorithm, each student will provide their code to their groupmate. If there is a group of 3 people (A, B, and C), then A gives their code to B, B gives their code to C, and C gives their code to A.
- Each student will write a main function that tests the code received from their groupmate. The main function should, upon execution, find the 5 intentionally introduced errors.
ATTENTION - the errors are secret (known ONLY to the person who introduced them in the code) and should not be communicated - the idea is to simulate a testing system that actually identifies these errors!