0% found this document useful (0 votes)
18 views33 pages

MatamGuide2

The document provides an overview of various design patterns in C++ and Python, categorized into behavioral, structural, and creational patterns. It includes detailed explanations and examples of patterns such as Iterator, Strategy, Command, Composite, Adapter, Decorator, Factory, and Abstract Factory. Additionally, it covers C++ basics, operator overloading, STL, and Python data structures and file handling.

Uploaded by

Yuval Yoran
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
18 views33 pages

MatamGuide2

The document provides an overview of various design patterns in C++ and Python, categorized into behavioral, structural, and creational patterns. It includes detailed explanations and examples of patterns such as Iterator, Strategy, Command, Composite, Adapter, Decorator, Factory, and Abstract Factory. Additionally, it covers C++ basics, operator overloading, STL, and Python data structures and file handling.

Uploaded by

Yuval Yoran
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 33

Sari Zrieq

‫תוכן העניינים‬
C++ ◆ Design Patterns
• Behavioral
o Iterator ............................................................................... 2
o Strategy......................................................................4
o Command ..................................................................5
• Structural
o Composite ................................................................6
o Adapter .....................................................................7
o Decorator ..................................................................8
• Creational
o Factory .....................................................................9
o Abstract Factory ...................................................... 10
o Singleton ................................................................. 11
◆ C++ basics (const, reference) ...................................................... 12
◆ Friends........................................................................................ 13
◆ Operator Overloading ................................................................. 13
◆ Function as a parameter ............................................................. 16
◆ Lambda....................................................................................... 15
◆ STL
• Using iterators in loops ....................................................... 16
• Vector ............................................................................... 17
• Map .................................................................................. 18
• Set .................................................................................... 19
• Pair & Tuple........................................................................ 19
• Queue ............................................................................... 20
• Smart Pointers ................................................................... 21
◆ Dynamic_casting ........................................................................ 21
◆ i/o stream ......................................................................... 22
◆ Exceptions ............................................................................................ 23
◆ Algorithm Library ................................................................................. 24
Python ◆ Data Structures
• String ................................................................................ 25
• List .................................................................................... 25
• Tuple ................................................................................. 26
• Set .................................................................................... 26
• Dictionary .......................................................................... 27
◆ List Comprehension .................................................................... 28
◆ Json ............................................................................................ 28
◆ File Handling ............................................................................... 29
◆ Exceptions .................................................................................. 30
◆ os and sys libraries ..................................................................... 31

Licensed under CC BY-NC 4.0 1


Sari Zrieq

Design Patterns

• Behavioral Design Patterns, these patterns define how objects interact


with each other and manage their communication in a clean and organized
way. They focus on the flow of control and information among different
objects to achieve a specific task. Examples of commonly used Behavioral
patterns:
▪ Iterator:
Purpose: Provides a way to access elements of a collection (like arrays or
lists) sequentially without exposing the underlying structure.
Use Case: When you need to iterate over a collection of objects without
knowing the details of its implementation
Key Words (for when to use iterators):
.‫ סדרה של אובייקטים‬,‫ רשימות‬,‫ גישה רציפה‬,‫מעבר על אוסף‬
Regular Iterator:
template <typename T>
//The base class we intend using iterator for
class MyClass{
public:
//...
class Iterator {
public:
// Constructor
Iterator(T* ptr) : ptr(ptr) {}
// Overloading * operator to access the value
T& operator*() {return *ptr;}
// Overloading ++ operator for pre-increment
Iterator& operator++() {
++ptr;
return *this;
}
// Overloading != operator to compare two iterators
bool operator!=(const Iterator& other) const {
return ptr != other.ptr;
}

private:
T* ptr; // Pointer to the current element
};
// We are outside the iterator class (inside MyClass)
// Begin iterator (points to the first element)
Iterator begin() {return Iterator(data);}

// End iterator (points to one past the last element)


Iterator end() {return Iterator(data + size);}
private:
//...
};

Licensed under CC BY-NC 4.0 2


Sari Zrieq

Const Iterator:
template <typename T>
class MyClass {
public:
// ...
class ConstIterator {
public:
// Constructor
ConstIterator(const T* ptr) : ptr(ptr) {}
// Overloading * operator to access the value
const T& operator*() const { return *ptr; }
// Overloading ++ operator for pre-increment
ConstIterator& operator++() {
++ptr;
return *this;
}
// Overloading != operator to compare two iterators
bool operator!=(const ConstIterator& other) const {
return ptr != other.ptr;
}
private:
const T* ptr; // Pointer to the current element (const)
};
// Const begin iterator
ConstIterator begin() const { return ConstIterator(data); }

// Const end iterator


ConstIterator end() const { return ConstIterator(data + size); }

private:
// ...
};

Explanation

• Iterator Class: This class allows modification of elements. The iterator


uses a raw pointer to access elements of the array.
• ConstIterator Class: This class provides read-only access to elements. It
uses a const T* pointer to ensure that the elements cannot be modified.
• Begin and End Methods:
o begin() and end() methods return iterators for both mutable and
immutable access.
o This allows you to use the class with range-based for loops for
both regular and const instances.

Example Usage

In the main() function You can create an instance of MyClass and iterate over its
elements using a range-based for loop, demonstrating both mutable and
immutable access.

Licensed under CC BY-NC 4.0 3


Sari Zrieq

▪ Strategy:
Purpose: Defines a family of algorithms, encapsulates each one, and
makes them interchangeable. The strategy pattern lets the algorithm vary
independently from clients that use it.
Use Case: When a class needs to perform a behavior (algorithm), but you
want to allow different behaviors to be defined and swapped at runtime.
Key Words (for when to use strategy):
.‫ פעולות משתנות לפי ההתנהגות הנקבעת‬,‫ בחירה בזמן ריצה‬,‫שינוי התנהגות‬
Example:

// Strategy Interface
class Strategy {
public:
virtual ~Strategy() = default;
virtual int execute(int a, int b) const = 0; // Pure virtual
function
};
// First strategy
class AddStrategy : public Strategy {
public:
int execute(int a, int b) const override {
return a + b;
}
};
// Second strategy
class MultiplyStrategy : public Strategy {
public:
int execute(int a, int b) const override {
return a * b;
}
};
// A Class that uses Strategy
class Calculator {
private:
std::unique_ptr<Strategy> strategy; // Pointer to Strategy
public:
// Constructor that accepts a strategy
explicit Calculator(std::unique_ptr<Strategy> strategy) :
strategy(std::move(strategy)) {}
// Set a new strategy at runtime
void setStrategy(std::unique_ptr<Strategy> newStrategy) {
strategy = std::move(newStrategy);
}
// Execute the strategy
int calculate(int a, int b) const {
return strategy->execute(a, b);
}
};

Licensed under CC BY-NC 4.0 4


Sari Zrieq

▪ Command:
Purpose: Encapsulates a request )‫ (פעולה‬as an object that contains all
the needed information to perform this request, therefore allowing us to
create store these requests objects in lists, queues….
Use Case: Used when different objects handle some requests differently,
or what requests an object should do or is allowed to do.
Key Words (for when to use command):
,(Encapsulation) ‫ הקניית פעולות‬,‫ עצירת ביצוע‬,(𝑈𝑛𝑑𝑜) ‫ ביטול פעולה‬,‫תורים של בקשות‬
.‫ים‬-‫מניפולציות על אוביקט‬

Example:

// Receiver Class
class Light {
public:
void turnOn() {}
void turnoff() {}
};
// Command Interface
class Command {
public:
virtual ~Command() = default;
virtual void execute() const = 0; // Pure virtual method for
executing the command
};
// Concrete Command to turn on the light
class LightOnCommand : public Command {
private:
Light& light;
public:
explicit LightOnCommand(Light& light) : light(light) {}
void execute() const override {light.turnOn();}
};
// Concrete Command to turn off the light
class LightOffCommand : public Command {
private:
Light& light;
public:
explicit LightOffCommand(Light& light) : light(light) {}
void execute() const override {light.turnOff();}
};
// Invoker Class
class RemoteControl {
private:
std::vector<std::unique_ptr<Command>> commands;
public:
void addCommand(std::unique_ptr<Command> command) {
commands.push_back(std::move(command));
}
void pressButton() const {
for (const auto& command : commands) {command->execute();}
}
};

Licensed under CC BY-NC 4.0 5


Sari Zrieq

• Structural Design Patterns, these patterns focus on how objects and


classes are structured and composed to form larger structures. They help to
organize code by forming relationships between entities, making systems
easier to understand and maintain. Examples of commonly used Structural
patterns:
▪ Composite:
Purpose: Composing objects that have a tree-like structure (explained in
structure section). This pattern allows clients to treat individual objects
that represent different items in the same category uniformly.
Structure:
o Component: A class (can be Abstract or
interface) that defines the common interface
for both leaf nodes and composite nodes.
o Leaf: Represents the end objects in the
hierarchy that do not have any children. They
implement the Component’s interface.
o Composite: Represents an object that
contains a list of leaves and/or composites.
It also implements the Component’s interface.
Use Case: When you want to treat different but related objects in the
same way, or group them in one list.
Key Words (for when to use composite):
.‫ הרחבה גמישה‬,‫ מבנה היררכי‬,‫ מכיל רשימת אובייקטים שונים‬,‫טיפול אחיד‬
Example:

class Musicians{
string name; //private field
public:
virtual string playSong(string songName) const = 0;
};

class Singer:public Musicians{


public:
string playSong(string songName) const override{}
};

class PianoPlayer:public Musicians{


public:
string playSong(string songName) const override{}
};

class Band:public Musicians{


vector<Musicians> bandMembers; //private field
public:
string playSong(string songName) const override{
string song = “”;
for (int © = 0; © < int(bandMembers.size()); i++)
{song += bandMembers[i].playSong(songName);}
return song;
}
};

Licensed under CC BY-NC 4.0 6


Sari Zrieq

▪ Adapter:
Purpose: Allowing incompatible interfaces to work together.
Use Case: When you have existing classes that don’t match the
interface you need, and you cannot or don’t want to modify them.
Key Words (for when to use adapter):
,‫ חיבור ממשקים‬.‫ שינוי ממשק‬,‫ אין לשנות את המחלקה‬,‫חוסר תאימות‬
Example:

// Existing Class (cannot be changed)


class Car {
public:
virtual ~Car() = default;
virtual void drive() const = 0; // Pure virtual function
};

// New Class (cannot be changed)


class ElectricCar {
public:
void startElectricEngine() const {
std::cout << “Electric engine started.” << std::endl;

void driveElectric() const {


std::cout << “Driving electric car silently.” << std::endl;
}
};

// Adapter Class that makes ElectricCar compatible with Car


class ElectricCarAdapter : public Car {
public:
explicit ElectricCarAdapter(ElectricCar* ec):electricCar(ec){}

void drive() const override {


// Adapting ElectricCar’s functionality
electricCar->startElectricEngine();

// Adapted method to fit the Car interface


electricCar->driveElectric();
}

private:
// Pointer to an ElectricCar instance
ElectricCar* electricCar;

};

Licensed under CC BY-NC 4.0 7


Sari Zrieq

▪ Decorator:

Purpose: Adds behavior or responsibilities to an object


dynamically without altering its structure.
Use Case: When you want to add functionality to objects without
affecting other objects of the same class.
Key Words (for when to use decorator):
‫ שיפור התנהגות‬,‫ גמישות בתכנון‬,‫ הרחבה דינמית‬,‫הוספת תכונות‬

Example:

// Simple coffee class


class Coffee {
public:
virtual string getDescription() const{
return “Simple Coffee”;
}
};

// Base Decorator
class CoffeeDecorator : public Coffee {
public:
explicit CoffeeDecorator(Coffee* c) : coffee© {}

// Delegate to the wrapped coffee


string getDescription() const override {
return coffee->getDescription();
}

protected:
Coffee* coffee; // Pointer to a Coffee object
};

// Concrete Decorator for Milk


class MilkDecorator : public CoffeeDecorator {
public:
explicit MilkDecorator(Coffee* c) : CoffeeDecorator© {}

//Add milk to description


string getDescription() const override {
return CoffeeDecorator::getDescription() + “, Milk”;
}
};

// you can add more concrete decorators

Licensed under CC BY-NC 4.0 8


Sari Zrieq

• Creational Design Patterns, these patterns provide ways to create


different objects according to some parameters and with some conditions.
They help manage object creation, ensuring that the right types of objects are
created and that the process is efficient and flexible. Examples of commonly
used Creational patterns:
▪ Factory:
Purpose: Providing a method for creating objects that let subclasses of
Factory class change the type of objects that will be created.
Use Case: When we want to create different classes (most of the times
subclasses for a Base class, for example, the Base class Job and his
subclasses teacher, writer, singer) according to inputs or parameters that
are changing during runtime.
Key Words (for when to use factory):
‫ סוגים משתנים‬,‫ מחלקות שונים‬,‫יצירת אובייקטים לפי פרמטרים‬

Example: creating a factory that generates candy based on the inputted


type:

enum CandyTypes{gummybears, icecream};

class Candy{};
class GummyBears:public Candy{};
class IceCream:public Candy{};

class CandyFactory{
public:
Candy* createCandy(CandyTypes type) const{
Candy* candy;
switch (type){
case (CandyTypes)gummybears:
candy = new GummyBears();
case (CandyTypes)icecream:
candy = new IceCream();
return candy;
}
}
};

int main() {
CandyFactory* candyFactory = new CandyFactory();
Candy* gummies = candyFactory->createCandy((CandyTypes)gummybears);
Candy* iceCream = candyFactory->createCandy((CandyTypes)icecream);
return 0;
}

Licensed under CC BY-NC 4.0 9


Sari Zrieq

▪ Abstract Factory:
Purpose: Providing an interface for creating related objects from the
same family or dependent objects without specifying their concrete
classes.
Use Case: When the system needs to be independent of how its products
are created, composed, or represented.
Key Words (for when to use abstract factory):
‫ הפרדה ממימוש קונקרטי‬,‫ גמישות במימוש‬,‫ יצירה מופשטת‬,‫משפחות של מוצרים‬

Example: Given the classes: in the first section you will have to build an
Abstract factory class like shown in the second section, and then we can
run the program as shown in the third section.

// Abstract Products
class Button {
public: virtual void paint() = 0;
};

class Checkbox {
public: virtual void render() = 0;
};

// Concrete Products
class WindowsButton : public Button {
public: void paint() override{cout << "Windows Button\n";}
};

class WindowsCheckbox : public Checkbox {


public: void render() override {cout << "Windows Checkbox\n";}
};

// Abstract Factory
class GUIFactory {
public:
virtual Button* createButton() = 0;
virtual Checkbox* createCheckbox() = 0;
};

// Concrete Factory
class WindowsFactory:public GUIFactory {
public:
Button* createButton() override
{ new WindowsButton();}
Checkbox* createCheckbox() override
{return new WindowsCheckbox();}
};

int main() {
GUIFactory* factory = new WindowsFactory();
factory->createButton()->paint();
factory->createCheckbox()->render();
delete factory;
}

Licensed under CC BY-NC 4.0 10


Sari Zrieq

▪ Singleton:
Purpose: Ensures that a class has only one instance and provides a
global point of access to that instance.
Use Case: When exactly one object is needed to coordinate actions
across the system.
Key Words (for when to use singleton):
.‫ בקרת גישה‬,‫ ניהול מצב משותף‬,‫ גישה גלובלית‬,‫מופע יחיד‬
How to use:

Game::getInstance().function();
//returns a instance for the singletone class

How to create a Singleton class: there is two common ways,

//there can be only one object, so we delete copy constructor and assign
operator

// the constructor should be private so users can’t create new Game objects

//the instance should only be initialized on the first use

//option 1:
class Game{
static Game* instance; // this will be initialized to nullptr
Game(){}
public:
static Game& getInstance() {
if (instance == nullptr) {
instance = new Game(); // this is called lazy initialization
}
return *instance;
}
static void destroy() { // the only way to clear the object

delete instance;
instance = nullptr;
}
Game(const Game& other) = delete;
Game& operator=(const Game& other) = delete;
};

//option 2:
class Game {
Game(){}
public:
static Game& getInstance() {
static Game instance; //created on first use
return instance; // guaranteed to be destroyed after exiting the block
}
Game(const Game& other) = delete;
Game& operator=(const Game& other) = delete;
};

Licensed under CC BY-NC 4.0 11


Sari Zrieq

C++ Basics
Const in c++: const ensures that a variable, parameter, or function return value
is read only, that means the value can’t be modified after initialization.
References in C++: A reference is like a nickname for a variable. Instead of
creating a new copy of the variable, a reference just points to the original
variable, so when you use the reference, you're working with the original data.
Passing by Value vs. Passing by Reference:
Passing by value: When an object is passed by value, a copy of the object is
made. Modifications to the object inside the function do not affect the original
object.

• Pros: Safe, because the function works with a copy of the data, avoiding
accidental changes to the original object.
• Cons: Can be inefficient if the object is large, because copying takes time
and memory.

When to use:

• When the object is small (like primitive types int, char, float).
• When you want to ensure the original object is not modified.

Passing by Reference: When an object is passed by reference, no copy is made,


and the function operates directly on the original object. This is more efficient for
large objects.

• Pros: Efficient, as no copy is made. Changes to the object inside the


function affect the original object.
• Cons: Less safe because the function can modify the original object
unless the reference is const.

When to use:

• When the object is large (like a vector, string, or a custom class).


• When you want to avoid unnecessary copying for performance reasons.
• When you need to modify the original object.
• When passing objects like streams (i/o fstream) that cannot be copied.
Passing by const Reference: Passing by const reference is used when you want
to avoid copying large objects but still ensure the function does not modify the
original object.
When to use:

• When the object is large, and you don’t want to copy it.
• When you don’t want the function to modify the original object.

Licensed under CC BY-NC 4.0 12


Sari Zrieq

Friends
Purpose: To grant external functions access to the private section of a class
Use case: for example, operator that is defined outside the class and needs to
access private fields

Operator Overloading
Purpose: allows user-defined types to behave intuitively, enabling familiar
syntax for operations, to enhances readability, and maintains consistency
across types.
What we cannot do:
Define new operators, change operators’ priority.
When overloading an operator, it should at least contain one user-defined type.
The “<<” and “>>” operators must be defined as non-members because their
first argument is an I/O stream, and not an object of the class.
Therefore, to grant them access to the private field of the class we should
define them as Friend inside the class.

class Matrix{
//...
friend ostream& operator<<(ostream& os, const Matrix& m);
}

You should also use friends at any operator that is defined outside the class
and needs to access private fields for example: For binary arithmetic operators,
you can use friend functions if you want to allow implicit type conversions or if
you want to operate on two different types.
Ways to define operators:

• Binary Operators:
o As a member function taking only one argument.
o As a nonmember function taking two arguments.
• Unary Operators:
o As a member function taking no arguments.
o As a nonmember function taking only one argument.

Licensed under CC BY-NC 4.0 13


Sari Zrieq

Common operators that we can override:

+ - * / = < > += -= *= /= [] () -> ++ --


Operators that we cannot override:

:: . ?: sizeof typeid
Assignment Operator:

// Overload the assignment operator


Matrix& operator=(const Matrix& other) {
if (this == &other) {
return *this;
}
rows = other.rows;
cols = other.cols;
data = other.data;
return *this;
}

Common Examples:

// Overload the += operator


Matrix& operator+=(const Matrix& other) {
if (rows != other.rows || cols != other.cols) {
throw invalid_argument("Mismatched Size");
}
for (size_t i = 0; i < rows; ++i) {
for (size_t j = 0; j < cols; ++j) {
data[i][j] += other.data[i][j];
}
}
return *this;
}

// Overload the + operator


Matrix operator+(const Matrix& other) const {
Matrix result = *this;
result += other;
return result;
}

// Overload the << operator for printing


friend ostream& operator<<(ostream& os, const Matrix& matrix) {
for (size_t i = 0; i < matrix.rows; ++i) {
for (size_t j = 0; j < matrix.cols; ++j) {
os << matrix.data[i][j] << " ";
}
os << endl;
}
return os;
}

Licensed under CC BY-NC 4.0 14


Sari Zrieq

Casting operator overloading:


operator Type() const; // implicit casting
explicit operator Type() const; // explicit casting
//use const if you want the return value to be read-only
Example:

class OtherType {//...}


class MyType {
//...
operator OtherType(){
// Conversion process
return result;
}
}

Lambda Expression
Basic syntax:
Capture List [capture]: Specifies which variables from the surrounding scope are
accessible inside the lambda. This can include by value ([x]), by reference ([&x]), or a
combination ([=, &x]).
Parameters (parameters): A list of parameters for the lambda, similar to a function’s
parameters.
Return Type -> return_type: Specifies the return type of the lambda. This is optional;
if omitted, the compiler infers the return type.
Function Body: The code to be executed when the lambda is called.

[capture](parameters) -> return_type {// function body}


3. Basic Lambda:

auto greet = []() {cout << “Hello, World!” << endl;};


2. Lambda with Parameters:

auto add = [](int a, int b) -> int {return a + b;};


3. Lambda with Capture List:

int x = 10;
auto byValue = [x]() {
cout << “Captured by value: “ << x << endl;
};

auto byReference = [&x]() {


cout << “Captured by reference: “ << x << endl;
};

Licensed under CC BY-NC 4.0 15


Sari Zrieq

Function as a parameter
To use a function as a parameter first you should define the as follows and then
you can give it a lambda function as its inputted function:

template<class Function>
void process(int x, Function func) {
func(x);
}

STL

Iterators (Vector, Set, Map):


object.begin() // returns an iterator to the beginning of the vector
object.end() // returns an iterator to the end of the vector
object.cbegin() // returns a const iterator to the beginning of the
vector
object.cend() // returns a const iterator to the beginning of the
vector

// how to use iterators


for(auto it = object.begin(); it != object.end(); ++it)
{cout << *it << endl}

You can use the following method if you class implements the necessary iterator
methods (begin() and end()) and provides the appropriate iterator operations.
Example of STL classes that support this:

Vector, list, deque, set, map, unordered_map, array, string.

for (const auto& item : items)


// remove the const if you want to make changes in the objects

Licensed under CC BY-NC 4.0 16


Sari Zrieq

Vector: usually used when we need a dynamic array.


• Initializing:

vector<int> vector;//Empty vector of integers


vector<int> vector(5);//Vector with 5 default-initialized elements
vector<int> vector(5, 10);//Vector with 5 elements, each initialized to 10

• Adding Elements:

vector.push_back(value) // Adds an element to the end of the vector.

• Accessing Elements:

int first = vector.front(); // First element


int last = vector.back(); // Last element
int element = vector [index]; // the (index + 1) element (0-based
indexing)

• Size:

int count = int(vector.size()); // Number of element


// Warning! if we don’t cast it to int vector.size() will return a
size_t object
bool isEmpty = vector.empty(); // Check if empty

• Modifying Elements:

vector.insert(vec.begin(), value); // Inserts a value at the beginning


vector.erase(vec.begin() + 1); // Remove the second element
vector.clear(); // Remove all elements
vector.resize(10); // Resize to 10 elements

Licensed under CC BY-NC 4.0 17


Sari Zrieq

For Set and Map: we can use the .count(value) method for sets it returns the
amount of values that match the input and for map it turns the amount of keys
that match the input but we know that set values and map values are unique
therefore we can use them to check if the input is already in the set or map or
not.

Map: Usually used when we need key-value pairs with unique keys.
• Initializing:

map<int, std::string> myMap; // Empty map


map<int, std::string> myMap = {{1, “one”}, {2, “two”}};
// Map with initial values

• Adding/Modifying Elements:

map.insert({3, “three”}); // Adds the key-value pair (3, “three”)


map [4] = “four”; // Adds or updates the key-value pair (4, “four”)
map[‘key’]; // if a key with the inserted value exists return a
reference to its value otherwise it creates a new value using the value
default constructor and the return a reference to its value.

• Removing Elements:

map.erase(2); // Removes the element with key 2


map.clear(); // Removes all elements

• Searching:

auto it = map.find(3);
if (it != map.end()) {
cout << “Key 3 found with the value: “ << it->second << endl;
}
//it->first points to the key, and it->second points to the value

• Accessing Elements:

string value = map.at(1); // Access the value associated with key 1

• Size:

int count = int(map.size()); // Number of elements


// Warning! if we don’t cast it to int map.size() will return a size_t
object
bool isEmpty = map.empty(); // Check if empty

Licensed under CC BY-NC 4.0 18


Sari Zrieq

Set: usually used when we need a collection of unique elements.


• Initializing:

set<int> mySet; // Empty set of integers


set<int> mySet = {1, 2, 3}; // Set initialized with elements 1, 2, 3

• Adding Elements:

set.insert(10); // Adds 10 to the set (if not already in set)

• Removing Elements:

set.erase(5); // Removes the element 5


set.clear(); // Removes all elements
• Searching:

if(mySet.find(value)!= mySet.end()){cout << “value in set” << endl;}

• Size:

Int count = int(set.size()); // Number of elements


// Warning! if we don’t cast it to int set.size() will return a size_t
object
bool isEmpty = set.empty(); // Check if empty

Pair: A simple container to store two different objects as a single unit.


Pair<int, string> myPair(1, “one”);
int num = myPair.first; // Accessing the first element
string str = myPair.second; // Accessing the second element

you can also create a pair using {} as follows:

queue<pair<int, BrewingMethod>> orders;


orders.push({3, HOT}); // this creates a pair on int and BrewingMethod
and pushes it into the queue orders

Tuple: Similar to pair but can store more than two objects.
Tuple<int, string, double> myTuple(1, “one”, 3.14);
auto [num, str, pi] = myTuple; // Structured binding

Licensed under CC BY-NC 4.0 19


Sari Zrieq

Queue:
• Initializing:

queue<int> q;

• Adding Elements:

q.push(10);

• Removing Elements:

q.pop();

• Accessing Elements:

int frontElement = q.front(); // Gets the element at the front of the queue
int backElement = q.back(); // Gets the element at the back of the queue

• Size:

int queueSize = int(q.size());


// returns number of elements in queue Warning!
//if we don’t cast it to int, q.size() will return a size_t object
bool isEmpty = q.empty(); // Checks if empty

Licensed under CC BY-NC 4.0 20


Sari Zrieq

Smart Pointers
unique_ptr: Owns a dynamically allocated object, and no two unique pointers
can own the same object. Transfers ownership using move().

unique_ptr<int> p1 = make_unique<int>(10);
unique_ptr <int> p2 = move(p1); // p1 is now empty

shared_ptr: Allows multiple pointers to manage the same object. Keeps a


reference count.

shared_ptr<int> sp1 = make_shared<int>(20);


shared_ptr <int> sp2 = sp1; // Both point to the same object

Dynamic Casting

Purpose: checks at runtime whether the cast is valid. If the cast fails, it returns
nullptr (for pointer types).
It only works with classes that have at least one virtual function

Use Case: dynamic_cast is useful when you need to ensure that you are working
with the correct type in a class hierarchy, especially when dealing with base
class pointers or references that could point to different derived class objects.
Example:

Base* basePtr = new Derived();

MyClass* test_object = dynamic_cast<MyClass*>(my_object);


if (derivedPtr) {
// if you got to here this object can be casted
} else {
// if you got to here this object cannot be casted
}

Licensed under CC BY-NC 4.0 21


Sari Zrieq

i/o stream

When using a file, you should always make sure to open the file before you use it
and close the file after you are done with it. Bad file management can cause
similar problems as bad memory management.
We read and write from files using >> and << operators
For reading from a file we can use the getline() function that has two variations:
istream& getline (istream& istream, string& str);
// istream, is the file we want to read from, str is where the line will be copied.
istream& getline (istream& is, string& str, char delimiter);
//it is almost like the function up there, but you can pick to stop after reading a
specific //char instead of the default being (new line (‘\n’)).
Constructors: //constructors get the filename and open the requested file so we
can use it.
ofstream file("output.txt");
ifstream file("input.txt");
Warning! fstream objects can’t be copied, if we want to send the object to a
function, we send it as a reference or send a pointer to the object.

Licensed under CC BY-NC 4.0 22


Sari Zrieq

Exceptions (C++)
Throwing an Exception: An exception is "thrown" when an error or unexpected
event occurs. Typically, exceptions are objects of a class that inherits from
exception.
Try Block: The try block contains the code that might throw an exception. If an
exception is thrown inside the try block, control is transferred to the appropriate
catch block.
Catch Block: The catch block handles the exception. You define one or more
catch blocks to specify how different types of exceptions should be handled.

try {
if (x == 0) {
throw runtime_error("Division by zero");
}
} catch (const runtime_error& e) {
cout << "Caught an exception: " << e.what() << endl;
}

Rethrowing Exceptions: You can rethrow an exception from within a catch block
using the throw statement if you want the exception to be handled at a higher
level.
Stack Unwinding: When an exception is thrown, C++ "unwinds" the stack. This
means it calls the destructors for all local objects created in the scope of the try
block before transferring control to the catch block. This is important for
managing resources like memory or file handles.

Exception Classes: C++ provides several standard exception classes that you
can use:

• exception: Base class for all exceptions in the standard library.


• runtime_error: Used for errors that are detectable only during runtime
(like dividing by zero).
• invalid_argument: Indicates an invalid argument was passed to a
function.
• out_of_range: Used when accessing elements outside the valid range
(like array bounds).
• bad_alloc: Thrown when a memory allocation fails.

Custom Exception Class:

class MyException : public exception {


const char* what() const noexcept override {
return “Error message”;
}
}

Licensed under CC BY-NC 4.0 23


Sari Zrieq

Algorithm Library

sort(begin, end); // this functions starts sorting from the first to second
parameter

vector<int> vec = {5, 2, 9, 1, 5, 6};


sort(vec.begin(), vec.end()); // vec is now {1, 2, 5, 5, 6, 9}

find(begin, end, value); //Searches for the first occurrence of a value in a range.

vector<int> vec = {1, 2, 3, 4, 5};


auto it = find(vec.begin(), vec.end(), 3);
// it points to the element '3'

count(begin, end, value); // Counts the occurrences of a specific value in a range.

vector<int> vec = {1, 2, 3, 1, 4, 1};


int count = count(vec.begin(), vec.end(), 1); // count is 3

Licensed under CC BY-NC 4.0 24


Sari Zrieq

Python
String:
• Initializing:

str1 = "" # Empty string or you can put any string you want
• Adding Elements:

str2 = str1 + " More text" # Concatenate strings


• Modifying Elements:

new_str = str1.replace("Hello", "Hi") # Replace part of the string


new_str = str1.lower()/.upper() #make the string lower/upper case
• Accessing Elements:

first_char = str1[0] # First character


last_char = str1[-1] # Last character
substring = str1[start:end] # Slice the string from 'start' to 'end'
• Size:

count = len(str1) # Number of characters

List:
• Initializing:

lst = [] # Empty list


lst = [1, 2, 3, 4] # List with initial elements
• Adding/Modifying Elements:

lst.append(value) # Adds an element to the end of the list


lst.insert(index, value) # Inserts an element at a specific position
lst[index] = new_value # Updates the value at a specific index
lst.sort() # Sorts the list in ascending order
• Removing Elements:

lst.remove(value) # Removes the first occurrence of the value


lst.pop(index) # Removes the element at the specified index
lst.clear() # Removes all elements
• Accessing Elements:

first = lst[0] # First element


last = lst[-1] # Last element
element = lst[index] # The (index + 1) element (0-based indexing)
• Size:

count = len(lst) # Number of elements


isEmpty = not lst # Check if empty

Licensed under CC BY-NC 4.0 25


Sari Zrieq

Tuple:
• Initializing:

tpl = () # Empty tuple


tpl = (1, 2, 3, 4) # Tuple with initial elements
tpl = (1,) # Single-element tuple (comma is required)
• Modifying Elements:

new_tpl = tpl + (5, 6) # Concatenate tuples to add new elements


new_tpl = tpl[:2] + (5,) + tpl[2:] # Insert an element at a specific index
• Accessing Elements:

first = tpl[0] # First element


last = tpl[-1] # Last element
element = tpl[index] # The (index + 1) element (0-based indexing)
• Size:

count = len(tpl) # Number of elements

Set:
• Initializing:

my_set = set() # Empty set


my_set = {1, 2, 3, 4} # Set with initial elements
• Adding/Modifying Elements:

my_set.add(value) # Adds an element to the set (duplicates are ignored)


• Removing Elements:

my_set.remove(value) # Removes the specified value (raises KeyError if


not found)
my_set.clear() # Removes all elements
• Accessing Elements:

exists = value in my_set # Check if a value exists in the set


• Size:

count = len(my_set) # Number of elements

Licensed under CC BY-NC 4.0 26


Sari Zrieq

Dictionary: A collection of key-value pairs, where each key is unique.


• Initializing:

dictionary = {} # Empty dictionary


dictionary = {'key1': 'value1', 'key2': 'value2'}
# Dictionary with initial key-value pairs

• Adding/Modifying Elements:

dictionary['new_key'] = 'new_value'
# Adds a new key-value pair or updates an existing key

• Removing Elements:

dictionary.pop('key1') # Removes the key-value pair by key


dictionary.clear() # Removes all elements

• Accessing Elements:

value = dictionary['key1'] # Access value by key


value = dictionary.get('key1', 'default_value')
# Access value with a default if key doesn't exist

• Size:

count = len(dictionary) # Number of key-value pairs


isEmpty = not dictionary # Check if empty

Licensed under CC BY-NC 4.0 27


Sari Zrieq

List Comprehension
Basic Syntax:
expression: The value or computation to include in the new list.
item: The variable representing each element in the iterable.
iterable: The collection or sequence to iterate over (e.g., list, range).
condition (optional): A filter that determines if the item should be included in the new
list.

[expression for item in iterable if condition]

JSON files
to store an object in a JSON file you should cast the object to a dictionary and then
saving each item inside this dictionary, and then you use json.dump() to put your item
inside a file:

// storing each item in a dictionary


def item_to_dict(item):
item_dect = {'name': item.name, 'weight': item.weight}

// storing the bag detaild and the items list in a disctionary


def store_bag(bag, path)
data = {
'capacity': bag.capacity,
'weight': bag.weight,
'items': [{'name':item.name, 'weight':item.weight}
for item in bag.items]
}
with open(path, 'w') as file:
json.dump(data, file)

Licensed under CC BY-NC 4.0 28


Sari Zrieq

File Handling

Opening a file:

file = open('filename.txt', 'r')# Open file for reading (default mode)

//using with.
with open('filename.txt', 'r') as file:
content = file.read()
# Process the content
# File is automatically closed after the block

Closing a file:

file.close()

Reading from a file:

# Read the entire file


content = file.read()

# Read one line at a time


line = file.readline()

# Read all lines into a list


lines = file.readlines()

Writing to a file:

file = open('filename.txt', 'w') # Open file for writing

file.write('Hello, World!\n')
file.writelines(['Line 1\n', 'Line 2\n'])

file.close() # Always close the file when done

Licensed under CC BY-NC 4.0 29


Sari Zrieq

Exceptions (Python)
In Python, we handle exceptions using a try-expect block. The code that might
raise an exception goes inside the try block, and the error-handling code goes
inside the expect block.

Key Elements:

• try: Wrap the code that may produce an exception.


• except: Define how to handle specific exceptions.
• else (optional): Executes if no exception occurs in the try block.
• finally (optional): Executes whether or not an exception occurs.

Common Python Exceptions:

• ZeroDivisionError: Division by zero.


• ValueError: Invalid value passed to a function.
• TypeError: Invalid operation on a data type.
• KeyError: Key not found in a dictionary.
• IndexError: Invalid list index.

Printing an error to the default error channel (stderr):

print("error message", file=sys.stderr)

Custom Exceptions:
# this class prints a message error using the exception constructor
class MyException(Exception):
def __init__(self):
super().__init__("error message")

# this class takes a string as a parameter and save it as a field


class MyException(Exception):
def __init__(self, error_string):
self.error_message = error_string

Licensed under CC BY-NC 4.0 30


Sari Zrieq

Useful Libraries
os Library:
Commonly used function:
os.path(file_name) # returns the path to the file name.
os.listdir(dir_name) # returns a list of the files that are in the dir
os.path.join(path, *paths) # Joins one or more path components intelligently.
os.path.split(path) # takes a file path as an argument and splits it into two
components: the directory path and the base file name. It returns a tuple containing
these two parts.

if you have a folder that contains files you can access each file using list
comprehension as follows:

[os.path.join(dir_name, file_name) for


file_name in os.listdir(dir_name)]

sys Library:
sys.exit(0) # or 1 usually 0 indicates success while 1 indicates an error.
sys.argv # A list that contains the command-line arguments passed to a script.

Licensed under CC BY-NC 4.0 31


Sari Zrieq

Hi, everyone!

I wrote this book to help me with my MATAM exam, and I'm excited to
share it with you so that everyone can benefit from it. I hope this
makes this especially challenging year a bit easier for you.

If you found this book helpful and it made a difference in your


understanding, I’d love to hear from you! Your feedback not only
helps me improve future editions but also guides other students in
finding useful resources. Please consider checking for new updates
at https://sarizrieq.github.io/book-landing-page/.

And hey, if you have any suggestions for improvements or additional


topics you'd like to see, feel free to contact me through email:
[email protected].

Thank you for letting this book be a part of your study journey. Best of
luck with your exams, you’re going to do great!

Warm regards,
Sari Zrieq

Licensed under CC BY-NC 4.0 32

You might also like