diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3d4692d..4e32591 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -93,6 +93,8 @@ set(APP_SOURCES
"src/core/datatypes/CStruct.cpp"
"src/core/datatypes/CUnion.cpp"
"src/core/datatypes/TypeConVersions.cpp"
+ ## Class
+ "src/core/datatypes/class/Friend.cpp"
"src/core/datatypes/class/CConstructors.cpp"
"src/core/datatypes/class/CDestructors.cpp"
"src/core/datatypes/class/SallowDeepCopying.cpp"
@@ -152,6 +154,18 @@ set(APP_SOURCES
"src/core/datatypes/smart_pointer/Unique.cpp"
"src/core/datatypes/smart_pointer/Shared.cpp"
"src/core/datatypes/smart_pointer/Weak.cpp"
+ ## Overloading
+ "src/core/overloading/ArithmeticOperator.cpp"
+ "src/core/overloading/IOOperator.cpp"
+ "src/core/overloading/UnaryOperator.cpp"
+ "src/core/overloading/ComparisonOperator.cpp"
+ "src/core/overloading/InDecOperator.cpp"
+ "src/core/overloading/SubscriptOperator.cpp"
+ "src/core/overloading/ParenthesisOperator.cpp"
+ "src/core/overloading/TypeCast.cpp"
+ "src/core/overloading/AssignmentOperator.cpp"
+ "src/core/overloading/ClassMemberAccessOperator.cpp"
+ "src/core/overloading/AllocationOperator.cpp"
)
# Test files
diff --git a/src/cembedded/README.md b/src/cembedded/README.md
new file mode 100644
index 0000000..e081882
--- /dev/null
+++ b/src/cembedded/README.md
@@ -0,0 +1,325 @@
+# 1. Core C Basics for Embedded Systems
+
+```
+Your Foundation for Embedded Programming
+```
+**Topics Covered:**
+
+- Variables & Data Types
+- Operators & Control Flow
+- Functions
+- Arrays & Strings
+- Basic Input/Output
+- Practice Problems
+
+## 1.1 Variables & Data Types
+
+**What is a Variable?**
+
+A variable is a named location in memory that stores data. Think of it as a labeled box
+where you can put values and retrieve them later.
+
+**Note:** In embedded systems, understanding how much memory each data type uses is
+CRITICAL because microcontrollers have limited RAM.
+
+**Common Data Types in C**
+
+| Data Type | Size (Typical) | Range | Use Case |
+|-----------------|---------------|------------------------------------|-----------------------------------|
+| char | 1 byte | -128 to 127 | Single characters, small integers |
+| unsigned char | 1 byte | 0 to 255 | Sensor readings, register values |
+| int (16-bit) | 2 bytes | -32,768 to 32,767 | Counters, calculations |
+| unsigned int | 2 bytes | 0 to 65,535 (16-bit) | Always positive values |
+| long | 4 bytes | -2,147,483,648 to 2,147,483,647 | Large numbers, timestamps |
+| float | 4 bytes | ±3.4e±38 (~6–7 digits precision) | Decimal numbers (avoid in embedded!) |
+
+**Example Code:**
+```c
+// Declaring variables
+int sensorValue = 0; // 16 or 32-bit integer
+unsigned char ledState = 1; // 8-bit (0-255)
+float temperature = 25.5; // Floating point
+char deviceStatus = 'A'; // Single character
+
+// Why size matters in embedded:
+unsigned char counter = 0; // Uses only 1 byte of RAM
+int bigCounter = 0; // Uses 2 or 4 bytes of RAM
+```
+
+
+
+## 1.2. Operators & Control Flow
+
+**Arithmetic Operators**
+
+Used for mathematical calculations: + (add), - (subtract), * (multiply), / (divide), %
+(modulus/remainder)
+```c
+int a = 10, b = 3;
+int sum = a + b; // 13
+int diff = a - b; // 7
+int product = a * b; // 30
+int quotient = a / b; // 3 (integer division!)
+int remainder = a % b; // 1
+```
+
+**Comparison Operators**
+
+Compare values and return true (1) or false (0):
+```c
+== (equal),
+!= (not equal),
+> (greater),
+< (less),
+>=, <=
+```
+
+**Logical Operators**
+
+Combine multiple conditions: && (AND), || (OR),! (NOT)
+
+```c
+int temperature = 75;
+int humidity = 60;
+
+// AND operator - both conditions must be true
+if (temperature > 70 && humidity > 50) {
+ printf("Hot and humid!\n");
+}
+```
+
+**Control Flow: if/else**
+
+Makes decisions in your program based on conditions.
+
+```c
+int temperature = 75;
+if (temperature > 80) {
+ // Turn on cooling fan
+ fanState = 1;
+} else if (temperature < 60) {
+ // Turn on heater
+ heaterState = 1;
+} else {
+ // Temperature is fine
+ fanState = 0;
+ heaterState = 0;
+}
+```
+
+**Loops: for and while**
+
+Repeat code multiple times. Essential for embedded systems!
+```c
+// for loop - when you know how many times to repeat
+for (int i = 0; i < 10; i++) {
+ printf("%d ", i); // Prints: 0 1 2 3 4 5 6 7 8 9
+}
+
+// while loop - repeat while condition is true
+int count = 0;
+while (count < 5) {
+ printf("Count: %d\n", count);
+ count++;
+}
+```
+
+> **Embedded Tip:** In embedded systems, you'll often use infinite loops: while(1) { } to
+keep the microcontroller running continuously!
+
+## 1.3. Functions
+
+**What are Functions?**
+
+Functions are reusable blocks of code that perform a specific task. They help you
+organize code and avoid repetition.
+
+**Function Structure**
+
+```c
+return_type function_name(parameters) {
+ // code to execute
+ return value; // optional
+}
+```
+
+**Example: Simple Functions**
+
+```c
+// Function that returns sum of two numbers
+int add(int a, int b) {
+ return a + b;
+}
+
+// Function that doesn't return anything (void)
+void blinkLED(int times) {
+ for (int i = 0; i < times; i++) {
+ // Turn LED on
+ // Delay
+ // Turn LED off
+ // Delay
+ }
+}
+
+// Using the functions
+int main() {
+ int result = add(5, 3); // result = 8
+ blinkLED(5); // Blink LED 5 times
+ return 0;
+}
+```
+
+> **Why Functions Matter in Embedded:** Real embedded projects have functions like
+readSensor(), updateDisplay(), checkButton() - breaking complex tasks into simple,
+manageable pieces.
+
+## 1.4. Arrays & Strings
+
+**What is an Array?**
+
+An array is a collection of elements of the same type stored in consecutive memory
+locations. Think of it as a row of boxes, each holding a value.
+
+**Declaring and Using Arrays**
+
+```c
+// Declare an array of 5 integers
+int sensorReadings[5];
+
+// Initialize array with values
+int ledPins[4] = {2, 3, 4, 5};
+
+// Access array elements (index starts at 0!)
+sensorReadings[0] = 100; // First element
+sensorReadings[1] = 105; // Second element
+sensorReadings[4] = 120; // Fifth element
+
+// Loop through array
+for (int i = 0; i < 5; i++) {
+ printf("%d ", sensorReadings[i]);
+}
+```
+
+**Strings in C**
+
+In C, strings are arrays of characters ending with a null terminator ('\0'). This is different
+from other languages!
+
+```c
+// Declaring strings
+char deviceName[] = "Arduino"; // Automatically adds \
+char message[20] = "Hello World"; // Reserve 20 chars
+
+// Character array vs string
+char name[6] = {'C', 'l', 'a', 'u', 'd', '\0'}; // Must add \
+
+// Common string operations (need string.h)
+#include
+char str1[50] = "Hello";
+char str2[50] = "World";
+strcat(str1, str2); // Concatenate: str1 becomes "HelloWorld"
+int len = strlen(str1); // Get length: 10
+strcpy(str1, "New"); // Copy: str1 becomes "New"
+```
+
+> **Important:** In embedded systems, you'll often use character arrays to store sensor
+data, messages for displays, or communication buffers.
+
+## 1.5. Basic Input/Output
+
+**Console Output: printf()**
+
+`printf()` is used to print formatted output to the console. Essential for debugging
+embedded systems!
+
+```c
+#include
+
+int temperature = 25;
+float voltage = 3.3;
+char status = 'A';
+
+// Format specifiers:
+printf("Temperature: %d°C\n", temperature); // %d for integers
+printf("Voltage: %.2f V\n", voltage); // %f for floats (.2 = 2 decimals)
+printf("Status: %c\n", status); // %c for characters
+printf("Hex value: 0x%X\n", 255); // %X for hexadecimal
+
+// Multiple values:
+printf("Temp: %d, Voltage: %.1f\n", temperature, voltage);
+```
+
+**Console Input: scanf()**
+
+`scanf()` reads formatted input from the console.
+
+```c
+int age;
+char name[50];
+
+printf("Enter your age: ");
+scanf("%d", &age); // Note the & symbol!
+
+printf("Enter your name: ");
+scanf("%s", name); // No & for arrays
+
+printf("Hello %s, you are %d years old!\n", name, age);
+```
+
+**Common Format Specifiers**
+
+| Specifier | Data Type | Example |
+|---------------|----------------|------------------------------|
+| %d or %i | int | printf("%d", 42); |
+| %u | unsigned int | printf("%u", 255); |
+| %f | float/double | printf("%.2f", 3.14); |
+| %c | char | printf("%c", 'A'); |
+| %s | string | printf("%s", "Hello"); |
+| %x or %X | hexadecimal | printf("0x%X", 255); |
+| %p | pointer | printf("%p", &var); |
+
+
+## 1.6. Practice Problems
+
+Here are some hands-on exercises to solidify your understanding. Try to solve these
+without looking at solutions first!
+
+**Problem 1: Temperature Converter**
+
+Write a program that converts temperature from Celsius to Fahrenheit using the
+formula: F = (C × 9/5) + 32
+
+// Your code here:
+// 1. Declare a float variable for celsius
+// 2. Use scanf to get input
+// 3. Calculate fahrenheit
+// 4. Print the result
+
+
+**Problem 2: Even or Odd Checker**
+
+Write a program that takes a number and prints whether it's even or odd. (Hint: Use the
+modulus operator %)
+
+**Problem 3: Sum Calculator with Loop**
+
+Write a program that takes a number N and calculates the sum of all numbers from 1 to
+N using a for loop.
+Example: If N = 5, sum = 1+2+3+4+5 = 15
+
+**Problem 4: Array Average**
+
+Create an array of 5 sensor readings. Write a function that calculates and returns the
+average value.
+
+**Problem 5: LED Blink Function**
+
+Write a function void blinkPattern(int count, int delayMs) that simulates blinking an LED.
+Use printf to show LED ON/OFF states.
+
+**Problem 5: Write a program that**
+- Takes 5 temperature readings into an array
+- Calculates the average temperature
+- If average > 75°F, print "COOLING NEEDED"
+- If average < 65°F, print "HEATING NEEDED"
+- Otherwise, print "TEMPERATURE OK"
diff --git a/src/core/datatypes/class/CConstructors.cpp b/src/core/datatypes/class/CConstructors.cpp
index 579f018..c605dc3 100644
--- a/src/core/datatypes/class/CConstructors.cpp
+++ b/src/core/datatypes/class/CConstructors.cpp
@@ -1,7 +1,12 @@
+// cppcheck-suppress-file [unusedVariable,unreadVariable]
#include
using namespace std;
-// *1. Members initializer list constructor
+// NOTE: We can throw an exception in a constructor to signal an error,
+// and then catch that error using a standard try-catch block
+// where the object is being instantiated.
+
+// **1. Members initializer list constructor**
namespace InitializerList {
class CConstructors {
private:
@@ -49,11 +54,10 @@ void constructers() {
}
} // namespace InitializerList
-// *2. Default constructor:
-// It is a constructor that accepts no arguments.
-// Generated if no constructors are declared
-// Initializes members: basic types uninitialized, class types call their
-// default constructor
+// **2. Default constructor**
+// - It is a constructor that accepts no arguments.
+// - Generated if no constructors are declared
+// - Initializes members: basic types uninitialized, class types call their default constructor
namespace Default {
class UConstructors {
public:
@@ -71,7 +75,7 @@ class EConstructors {
public:
// we already create the constructor ourselves
// EConstructors(int a)
- explicit EConstructors(float a) // explicit -> [[maybe_unused]]
+ explicit EConstructors(float a) // explicit ->
// EConstructors obj2 = 1; [ERROR]
{
@@ -85,8 +89,8 @@ class EConstructors {
void constructers() {
cout << "\n--- Default Constructer Examples ---\n";
- [[maybe_unused]] UConstructors obj1;
- // [[maybe_unused]] UConstructors obj2(); // wrong, this is function declare
+ UConstructors obj1;
+ // UConstructors obj2(); // wrong, this is function declare
// FYI:
// void outer()
// {
@@ -94,20 +98,20 @@ void constructers() {
// helper(); // defined later in the same file
// }
- [[maybe_unused]] UConstructors obj3{};
+ UConstructors obj3{};
- [[maybe_unused]] IConstructors obj4;
- [[maybe_unused]] IConstructors obj6{};
+ IConstructors obj4;
+ IConstructors obj6{};
- [[maybe_unused]] EConstructors obj7;
- [[maybe_unused]] EConstructors obj9{};
+ EConstructors obj7;
+ EConstructors obj9{};
- [[maybe_unused]] EConstructors obj10(1.2);
- [[maybe_unused]] EConstructors obj11{2};
+ EConstructors obj10(1.2);
+ EConstructors obj11{2};
}
} // namespace Default
-// *3. Delegate constructor: allow to delegate initialization to another
+// **3. Delegate constructor: allow to delegate initialization to another**
// constructor Never generated automatically
namespace Delegate {
class CConstructor {
@@ -138,9 +142,9 @@ void constructors() {
}
} // namespace Delegate
-// *4. Copy constructor: initialize an copy object with an existing object
-// Generated if no copy/move constructor or `destructor` is declared
-// Performs memberwise (shallow) copy
+// **4. Copy constructor: initialize an copy object with an existing object**
+// - Generated if no copy/move constructor or `destructor` is declared
+// - Performs memberwise (shallow) copy
// * Copy constructor
// Object obj1 = obj2
// Object obj1(obj2)
@@ -232,11 +236,11 @@ void constructors() {
}
} // namespace Copy
-// *4. Move Constructor:
-// Move constructor and move assignment transfer resource ownership
-// from one object to another. This is usually cheaper than copying.
-// A move constructor is implicitly generated only if no user-declared
-// copy constructor, move constructor, or destructor exists.
+// **4. Move Constructor**
+// - Move constructor and move assignment transfer resource ownership
+// - from one object to another. This is usually cheaper than copying.
+// - A move constructor is implicitly generated only if no user-declared
+// copy constructor, move constructor, or destructor exists.
namespace Move {
class Model // C++ will create a public implicit copy constructor for us if we
// do not provide a one.
@@ -306,7 +310,7 @@ void constructers() {
class CConstructors : public IExample {
public:
- std::string group() const override { return "core"; }
+ std::string group() const override { return "core/class"; }
std::string name() const override { return "CConstructors"; }
std::string description() const override { return ""; }
void execute() override {
@@ -318,4 +322,4 @@ class CConstructors : public IExample {
}
};
-REGISTER_EXAMPLE(CConstructors, "core", "CConstructors");
+REGISTER_EXAMPLE(CConstructors, "core/class", "CConstructors");
diff --git a/src/core/datatypes/class/CDestructors.cpp b/src/core/datatypes/class/CDestructors.cpp
index 64bc62b..721c40a 100644
--- a/src/core/datatypes/class/CDestructors.cpp
+++ b/src/core/datatypes/class/CDestructors.cpp
@@ -1,10 +1,10 @@
#include
using namespace std;
-// *1. Basic Destructor
-// Generated if no destructor is declared
-// Calls destructors of members automatically
-// Does not free dynamically allocated memory unless you write it
+// ** 1. Basic Destructor**
+// - Generated if no destructor is declared
+// - Calls destructors of members automatically
+// - Does not free dynamically allocated memory unless you write it
namespace Basic {
class CDestructors {
public:
@@ -25,7 +25,7 @@ void destructers() {
}
} // namespace Basic
-// *2. Virtual Destructor
+// **2. Virtual Destructor**
namespace Virtual {
class CDestructorsBase // final => cannot inherit
{
@@ -61,7 +61,7 @@ void destructers() {
class CDestructors : public IExample {
public:
- std::string group() const override { return "core"; }
+ std::string group() const override { return "core/class"; }
std::string name() const override { return "CDestructors"; }
std::string description() const override { return ""; }
void execute() override {
@@ -70,4 +70,4 @@ class CDestructors : public IExample {
}
};
-REGISTER_EXAMPLE(CDestructors, "core", "CDestructors");
+REGISTER_EXAMPLE(CDestructors, "core/class", "CDestructors");
diff --git a/src/core/datatypes/class/Friend.cpp b/src/core/datatypes/class/Friend.cpp
new file mode 100644
index 0000000..99fb666
--- /dev/null
+++ b/src/core/datatypes/class/Friend.cpp
@@ -0,0 +1,124 @@
+// cppcheck-suppress-file [functionStatic]
+#include
+#include "ExampleRegistry.h"
+namespace {
+namespace NonMember {
+
+class Accumulator {
+ private:
+ int value_{0};
+
+ public:
+ void add(int value) { value_ += value; }
+
+ // print out the Accumulator use <<
+ // S1: Overloading
+ std::ostream& operator<<(std::ostream& os) const {
+ os << "S1: " << value_ << "\n";
+ return os;
+ }
+
+ // S2: Friend
+ friend std::ostream& operator<<(std::ostream& os, const Accumulator& acc);
+};
+
+std::ostream& operator<<(std::ostream& os, const Accumulator& acc) {
+ os << "S2: " << acc.value_ << "\n";
+ return os;
+}
+
+void run() {
+ Accumulator acc{};
+ acc.add(5);
+
+ // Use S1:
+ acc << std::cout; // backward and weird
+
+ // Use S2: expect std::cout << acc;
+ std::cout << acc; // good
+}
+
+} // namespace NonMember
+
+namespace Member {
+class Accumulator;
+class Display {
+ public:
+ void f_display(const Accumulator& acc) const;
+
+ void display(const Accumulator& acc) const;
+};
+
+class Accumulator {
+ private:
+ int value_{0};
+
+ public:
+ void add(int value) { value_ += value; }
+
+ // Make Display class a friend of Acc
+ friend void Display::f_display(const Accumulator& acc) const;
+};
+
+void Display::f_display(const Accumulator& acc) const{
+ std::cout << "S4: " << acc.value_ << "\n";
+}
+
+void Display::display(const Accumulator& acc) const {
+ // std::cout << "S4: " << acc.value_ << "\n"; // cannot access
+}
+
+void run() {
+ Accumulator acc{};
+ acc.add(-99);
+ Display d{};
+ d.display(acc);
+ d.f_display(acc);
+}
+} // namespace Member
+
+} // namespace
+
+namespace Class {
+
+class Display;
+class Accumulator {
+ private:
+ int value_{0};
+
+ public:
+ void add(int value) { value_ += value; }
+
+ // Make Display class a friend of Acc
+ friend class Display;
+};
+
+class Display {
+ public:
+ void display(const Accumulator& acc) {
+ std::cout << "S3: " << acc.value_ << "\n";
+ }
+};
+
+void run() {
+ Accumulator acc{};
+ acc.add(99);
+ Display d{};
+ d.display(acc);
+}
+} // namespace Class
+
+class Friend : public IExample {
+ std::string group() const override { return "core/class"; };
+
+ std::string name() const override { return "Friend"; };
+ std::string description() const override { return "Friend examples"; };
+
+ void execute() override {
+ NonMember::run();
+ Member::run();
+ Class::run();
+ };
+};
+
+REGISTER_EXAMPLE(Friend, "core/class", "Friend");
\ No newline at end of file
diff --git a/src/core/datatypes/class/README.md b/src/core/datatypes/class/README.md
new file mode 100644
index 0000000..6e7c99b
--- /dev/null
+++ b/src/core/datatypes/class/README.md
@@ -0,0 +1,18 @@
+## 1. Friend
+- Friend declaration (classes and functions) allows certain classes or functions to access the private and protected members of another class.
+
+### 1.1. Non Member Function
+- It serves the same kind of role as the package access specifier in Java.
+- `a << b` C++ tries in this order:
+```cpp
+1 a.operator<<(b)
+2 operator<<(a, b) (non-member function)
+
+X OP Y
+operator OP (type_of_X, type_of_Y)
+```
+### 1.2. Member of Another Class:
+- It give access to only once specific function.
+### 1.3. Class
+- Friend Class : I trust this class to see my private data
+- It give access to all member functions of another class.
\ No newline at end of file
diff --git a/src/core/overloading/AllocationOperator.cpp b/src/core/overloading/AllocationOperator.cpp
new file mode 100644
index 0000000..ed20907
--- /dev/null
+++ b/src/core/overloading/AllocationOperator.cpp
@@ -0,0 +1,99 @@
+// cppcheck-suppress-file [functionConst]
+
+// Overloading operator new, delete
+// Debug
+
+#include
+#include "ExampleRegistry.h"
+namespace {
+
+class IntCollection {
+ private:
+ int m_data[3]{10, 20, 30};
+
+ public:
+ class Iterator {
+ private:
+ int* m_ptr;
+
+ public:
+ explicit Iterator(int* ptr) : m_ptr(ptr) {}
+
+ int& operator*() { return *m_ptr; }
+
+ int* operator->() { return m_ptr; }
+
+ Iterator& operator++() {
+ ++m_ptr;
+ return *this;
+ }
+
+ bool operator!=(const Iterator& other) const {
+ return m_ptr != other.m_ptr;
+ }
+ };
+
+ Iterator begin() { return Iterator(m_data); }
+ Iterator end() { return Iterator(m_data + 3); }
+
+ // int* a = new int;
+ void* operator new(size_t size) {
+ std::cout << "void* operator new(size_t size)\n";
+ // void* p = ::operator new(size);
+ void* p = malloc(size);
+ if (!p)
+ throw std::bad_alloc();
+ return p;
+ }
+
+ // delete a
+ void operator delete(void* p) {
+ std::cout << "void operator delete(void* p)\n";
+ free(p);
+ }
+
+ // int* as = new int[100]
+ void* operator new[](size_t size) {
+ std::cout << "void* operator new[](size_t size)\n";
+ void* p = malloc(size);
+ if (!p)
+ throw std::bad_alloc();
+ return p;
+ }
+
+ // delete []as;
+ void operator delete[](void* p) {
+ std::cout << "void operator delete[](void* p)\n";
+ free(p);
+ }
+};
+
+void run() {
+ IntCollection* col = new IntCollection;
+
+ for (auto it = col->begin(); it != col->end(); ++it) {
+ std::cout << *it << '\n';
+ }
+
+ delete col;
+
+ IntCollection* cols = new IntCollection[10];
+ for (int i = 0; i < 10; ++i) {
+ for (auto it = cols[i].begin(); it != cols[i].end(); ++it) {
+ std::cout << *it << '\n';
+ }
+ }
+ delete[] cols;
+}
+} // namespace
+
+class AllocationOperator : public IExample {
+ public:
+ std::string group() const override { return "core/overloading"; }
+ std::string name() const override { return "AllocationOperator"; }
+ std::string description() const override { return ""; }
+
+ void execute() override { run(); }
+};
+
+REGISTER_EXAMPLE(AllocationOperator, "core/overloading", "AllocationOperator");
\ No newline at end of file
diff --git a/src/core/overloading/ArithmeticOperator.cpp b/src/core/overloading/ArithmeticOperator.cpp
new file mode 100644
index 0000000..0506024
--- /dev/null
+++ b/src/core/overloading/ArithmeticOperator.cpp
@@ -0,0 +1,82 @@
+// cppcheck-suppress-file[]
+// + - * /
+#include
+#include "ExampleRegistry.h"
+
+namespace {
+class Cents {
+ private:
+ int m_cents{};
+
+ public:
+ explicit Cents(int cents) : m_cents{cents} {}
+ int getCents() const { return m_cents; }
+
+ // Problem: A member operator only works when the left-hand operand is an object of the class (e.g., Cents).
+ // Cents sum = 5 + s1;
+ // int.operator+(5)
+ // => error
+ // Cents operator+(const Cents& other) {
+ // return Cents{this->getCents() + other.getCents()};
+ // }
+
+ // For operands of different types
+ friend Cents operator+(int v1, const Cents& c2) {
+ return Cents{v1 + c2.getCents()};
+ }
+
+ friend Cents operator+(const Cents& c1, int v2) {
+ return Cents{v2 + c1.getCents()};
+ }
+
+ // ArithmeticOperator operators
+ friend Cents operator+(const Cents& c1, const Cents& c2) {
+ return Cents{c1.getCents() + c2.getCents()};
+ }
+
+ friend Cents operator-(const Cents& c1, const Cents& c2) {
+ return Cents{c1.getCents() - c2.getCents()};
+ }
+
+ friend Cents operator*(const Cents& c1, const Cents& c2) {
+ return Cents{c1.getCents() * c2.getCents()};
+ }
+
+ friend Cents operator/(const Cents& c1, const Cents& c2) {
+ return Cents{c1.getCents() / c2.getCents()};
+ }
+};
+
+void run() {
+ Cents c1{25};
+ Cents c2{75};
+
+ // Sum
+ Cents sum = c1 + c2;
+ Cents sum2 = operator+(125, c2);
+ std::cout << "Sum: " << sum.getCents() << " " << sum2.getCents() << std::endl;
+
+ // Sub
+ Cents sub = c1 - c2;
+ std::cout << "Sub: " << sub.getCents() << std::endl;
+
+ // Div
+ Cents div = c1 / c2;
+ std::cout << "Div: " << div.getCents() << std::endl;
+
+ // Mul
+ Cents mul = c1 * c2;
+ std::cout << "Mul: " << mul.getCents() << std::endl;
+}
+} // namespace
+
+class ArithmeticOperator : public IExample {
+ public:
+ std::string group() const override { return "core/overloading"; }
+ std::string name() const override { return "ArithmeticOperator"; }
+ std::string description() const override { return ""; }
+
+ void execute() override { run(); }
+};
+
+REGISTER_EXAMPLE(ArithmeticOperator, "core/overloading", "ArithmeticOperator");
\ No newline at end of file
diff --git a/src/core/overloading/AssignmentOperator.cpp b/src/core/overloading/AssignmentOperator.cpp
new file mode 100644
index 0000000..f5a4fad
--- /dev/null
+++ b/src/core/overloading/AssignmentOperator.cpp
@@ -0,0 +1,51 @@
+// cppcheck-suppress-file [unreadVariable]
+
+// Overloading operator=
+
+#include
+#include "ExampleRegistry.h"
+
+namespace {
+class Cents {
+ private:
+ int m_cents{};
+
+ public:
+ explicit Cents(int cents = 0) : m_cents{cents} {}
+
+ int getCents() const { return m_cents; }
+ void setCents(int cents) { m_cents = cents; }
+
+ // Copy constructor
+ Cents(const Cents& other) {
+ std::cout << "Cents(const Cents& other)\n";
+ m_cents = other.m_cents;
+ }
+
+ // Overload copy assignment
+ Cents& operator=(const Cents& cents) {
+ // do the copy
+ std::cout << "Cents& operator=(const Cents& cents)\n";
+ m_cents = cents.m_cents;
+ return *this;
+ }
+};
+
+void run() {
+ Cents c1{100};
+ Cents c2;
+ c2 = c1; // calls overloaded copy assignment
+ Cents c3 = c1; // calls copy constructor because c3 didn't exist yet
+}
+} // namespace
+
+class AssignmentOperator : public IExample {
+ public:
+ std::string group() const override { return "core/overloading"; }
+ std::string name() const override { return "AssignmentOperator"; }
+ std::string description() const override { return ""; }
+
+ void execute() override { run(); }
+};
+
+REGISTER_EXAMPLE(AssignmentOperator, "core/overloading", "AssignmentOperator");
\ No newline at end of file
diff --git a/src/core/overloading/ClassMemberAccessOperator.cpp b/src/core/overloading/ClassMemberAccessOperator.cpp
new file mode 100644
index 0000000..130b43f
--- /dev/null
+++ b/src/core/overloading/ClassMemberAccessOperator.cpp
@@ -0,0 +1,65 @@
+// cppcheck-suppress-file []
+
+// Overloading operator-> *.
+// Collection item
+
+#include
+#include "ExampleRegistry.h"
+namespace {
+
+class IntCollection {
+ private:
+ int m_data[3]{10, 20, 30};
+
+ public:
+ class Iterator {
+ private:
+ int* m_ptr;
+
+ public:
+ explicit Iterator(int* ptr) : m_ptr(ptr) {}
+
+ int& operator*() {
+ std::cout << "int& operator*()\n";
+ return *m_ptr;
+ }
+
+ int* operator->() {
+ std::cout << "int* operator->()\n";
+ return m_ptr;
+ }
+
+ Iterator& operator++() {
+ ++m_ptr;
+ return *this;
+ }
+
+ bool operator!=(const Iterator& other) const {
+ return m_ptr != other.m_ptr;
+ }
+ };
+
+ Iterator begin() { return Iterator(m_data); }
+ Iterator end() { return Iterator(m_data + 3); }
+};
+
+void run() {
+ IntCollection col;
+
+ for (auto it = col.begin(); it != col.end(); ++it) {
+ std::cout << *it << '\n';
+ }
+}
+} // namespace
+
+class ClassMemberAccessOperator : public IExample {
+ public:
+ std::string group() const override { return "core/overloading"; }
+ std::string name() const override { return "ClassMemberAccessOperator"; }
+ std::string description() const override { return ""; }
+
+ void execute() override { run(); }
+};
+
+REGISTER_EXAMPLE(ClassMemberAccessOperator, "core/overloading",
+ "ClassMemberAccessOperator");
\ No newline at end of file
diff --git a/src/core/overloading/ComparisonOperator.cpp b/src/core/overloading/ComparisonOperator.cpp
new file mode 100644
index 0000000..ff6c68e
--- /dev/null
+++ b/src/core/overloading/ComparisonOperator.cpp
@@ -0,0 +1,47 @@
+// cppcheck-suppress-file[]
+
+#include
+#include "ExampleRegistry.h"
+
+namespace {
+class Cents {
+ private:
+ int m_cents{};
+
+ public:
+ explicit Cents(int cents) : m_cents{cents} {}
+ int getCents() const { return m_cents; }
+
+ auto operator<=> (const Cents&) const = default; // std 20
+ // friend bool operator== (const Cents& c1, const Cents& c2) { return c1.m_cents == c2.m_cents; }
+ // friend bool operator!= (const Cents& c1, const Cents& c2) { return !(operator==(c1, c2)); }
+
+ // friend bool operator< (const Cents& c1, const Cents& c2) { return c1.m_cents < c2.m_cents; }
+ // friend bool operator> (const Cents& c1, const Cents& c2) { return operator<(c2, c1); }
+
+ // friend bool operator<= (const Cents& c1, const Cents& c2) { return !(operator>(c1, c2)); }
+ // friend bool operator>= (const Cents& c1, const Cents& c2) { return !(operator<(c1, c2)); }
+};
+
+void run() {
+ Cents pt1{25};
+ Cents pt2{30};
+ std::cout << std::boolalpha << (pt1 == pt2) << ' ' // false
+ << (pt1 != pt2) << ' ' // true
+ << (pt1 < pt2) << ' ' // true
+ << (pt1 <= pt2) << ' ' // true
+ << (pt1 > pt2) << ' ' // false
+ << (pt1 >= pt2) << ' '; // false
+}
+} // namespace
+
+class ComparisonOperator : public IExample {
+ public:
+ std::string group() const override { return "core/overloading"; }
+ std::string name() const override { return "ComparisonOperator"; }
+ std::string description() const override { return ""; }
+
+ void execute() override { run(); }
+};
+
+REGISTER_EXAMPLE(ComparisonOperator, "core/overloading", "ComparisonOperator");
\ No newline at end of file
diff --git a/src/core/overloading/IOOperator.cpp b/src/core/overloading/IOOperator.cpp
new file mode 100644
index 0000000..3b1c42f
--- /dev/null
+++ b/src/core/overloading/IOOperator.cpp
@@ -0,0 +1,64 @@
+// cppcheck-suppress-file[]
+
+// >> <<
+#include
+#include "ExampleRegistry.h"
+
+namespace {
+class Cents {
+ private:
+ int m_cents{};
+
+ public:
+ explicit Cents(int cents) : m_cents{cents} {}
+ int getCents() const { return m_cents; }
+
+ // // We won’t be able to use a member overload if the left operand is either not a class (e.g. int),
+ // // or it is a class that we can’t modify (e.g. std::ostream).
+ // // _cents << std::cout; work
+ // // std::cout << _cents; error
+ // std::ostream& operator<<(std::ostream& out) {
+ // out << m_cents;
+ // return out;
+ // }
+};
+
+std::ostream& operator<<(std::ostream& out, const Cents& c) {
+ out << c.getCents();
+ return out;
+}
+
+std::istream& operator>>(std::istream& in, Cents& c) {
+ int cents{};
+ in >> cents;
+ c = in ? Cents{cents} : Cents{0};
+ return in;
+}
+
+void run() {
+ Cents c1{25};
+ // out >>
+ std::cout
+ << c1
+ << "\n"; // operator<<(std::cout, c1) -> operator<<(std::ostream,Cents)
+
+ // in >>
+ std::cin >> c1; // operator>>(std::cin,c1) -> operator<<(std::istream,Cents)
+ std::cout << c1 << "\n";
+
+ // clearing lefover newline
+ std::string line;
+ std::getline(std::cin, line);
+}
+} // namespace
+
+class IOOperator : public IExample {
+ public:
+ std::string group() const override { return "core/overloading"; }
+ std::string name() const override { return "IOOperator"; }
+ std::string description() const override { return ""; }
+
+ void execute() override { run(); }
+};
+
+REGISTER_EXAMPLE(IOOperator, "core/overloading", "IOOperator");
\ No newline at end of file
diff --git a/src/core/overloading/InDecOperator.cpp b/src/core/overloading/InDecOperator.cpp
new file mode 100644
index 0000000..fb68573
--- /dev/null
+++ b/src/core/overloading/InDecOperator.cpp
@@ -0,0 +1,66 @@
+// cppcheck-suppress-file [postfixOperator]
+
+// prefix/posfix
+#include
+#include "ExampleRegistry.h"
+
+namespace {
+class Cents {
+ private:
+ int m_cents{};
+
+ public:
+ explicit Cents(int cents) : m_cents{cents} {}
+ int getCents() const { return m_cents; }
+
+ // pre: inc -> return new
+ Cents& operator++();
+ Cents& operator--();
+
+ // return old -> inc
+ Cents operator++(int);
+ Cents operator--(int);
+};
+
+// pre ++x/--x
+Cents& Cents::operator++() {
+ ++m_cents;
+ return *this;
+}
+Cents& Cents::operator--() {
+ --m_cents;
+ return *this;
+}
+
+// pos x++/x--
+Cents Cents::operator++(int) {
+ Cents temp{*this}; // create copy
+ ++(*this); // increase origin
+ return temp; // return old
+}
+Cents Cents::operator--(int) {
+ Cents temp{*this};
+ --(*this);
+ return temp;
+}
+
+void run() {
+ Cents cent{25};
+ cent++;
+ ++cent;
+ cent--;
+ --cent;
+ std::cout << cent.getCents() << "\n";
+}
+} // namespace
+
+class InDecOperator : public IExample {
+ public:
+ std::string group() const override { return "core/overloading"; }
+ std::string name() const override { return "InDecOperator"; }
+ std::string description() const override { return ""; }
+
+ void execute() override { run(); }
+};
+
+REGISTER_EXAMPLE(InDecOperator, "core/overloading", "InDecOperator");
\ No newline at end of file
diff --git a/src/core/overloading/ParenthesisOperator.cpp b/src/core/overloading/ParenthesisOperator.cpp
new file mode 100644
index 0000000..ec8f1c3
--- /dev/null
+++ b/src/core/overloading/ParenthesisOperator.cpp
@@ -0,0 +1,50 @@
+// cppcheck-suppress-file []
+
+// operator()
+#include
+#include "ExampleRegistry.h"
+
+namespace {
+#include // for assert()
+
+class Matrix {
+ private:
+ double m_data[4][4]{};
+
+ public:
+ double& operator()(int row, int col);
+ double operator()(int row, int col) const; // for const objects
+};
+
+double& Matrix::operator()(int row, int col) {
+ assert(row >= 0 && row < 4);
+ assert(col >= 0 && col < 4);
+
+ return m_data[row][col];
+}
+
+double Matrix::operator()(int row, int col) const {
+ assert(row >= 0 && row < 4);
+ assert(col >= 0 && col < 4);
+
+ return m_data[row][col];
+}
+
+void run() {
+ Matrix matrix;
+ matrix(1, 2) = 4.5;
+ std::cout << matrix(1, 2) << '\n';
+}
+} // namespace
+
+class ParenthesisOperator : public IExample {
+ public:
+ std::string group() const override { return "core/overloading"; }
+ std::string name() const override { return "ParenthesisOperator"; }
+ std::string description() const override { return ""; }
+
+ void execute() override { run(); }
+};
+
+REGISTER_EXAMPLE(ParenthesisOperator, "core/overloading",
+ "ParenthesisOperator");
\ No newline at end of file
diff --git a/src/core/overloading/SubscriptOperator.cpp b/src/core/overloading/SubscriptOperator.cpp
new file mode 100644
index 0000000..a1896c1
--- /dev/null
+++ b/src/core/overloading/SubscriptOperator.cpp
@@ -0,0 +1,44 @@
+// cppcheck-suppress-file[]
+
+// >> <<
+#include
+#include "ExampleRegistry.h"
+
+namespace {
+
+class IntList {
+ private:
+ int m_list[10]{
+ 0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9}; // give this class some initial state for this example
+
+ public:
+ // For non-const objects: can be used for assignment
+ int& operator[](int index) { return m_list[index]; }
+
+ // For const objects: can only be used for access
+ // This function could also return by value if the type is cheap to copy
+ const int& operator[](int index) const { return m_list[index]; }
+};
+
+void run() {
+ IntList list{};
+ list[2] = 3; // okay: calls non-const version of operator[]
+ std::cout << list[2] << '\n';
+
+ const IntList clist{};
+ // clist[2] = 3; // compile error: clist[2] returns const reference, which we can't assign to
+ std::cout << clist[2] << '\n';
+}
+} // namespace
+
+class SubscriptOperator : public IExample {
+ public:
+ std::string group() const override { return "core/overloading"; }
+ std::string name() const override { return "SubscriptOperator"; }
+ std::string description() const override { return ""; }
+
+ void execute() override { run(); }
+};
+
+REGISTER_EXAMPLE(SubscriptOperator, "core/overloading", "SubscriptOperator");
\ No newline at end of file
diff --git a/src/core/overloading/TypeCast.cpp b/src/core/overloading/TypeCast.cpp
new file mode 100644
index 0000000..ce8fa35
--- /dev/null
+++ b/src/core/overloading/TypeCast.cpp
@@ -0,0 +1,61 @@
+// cppcheck-suppress-file []
+
+// Overloading typecast
+
+#include
+#include "ExampleRegistry.h"
+
+namespace {
+class Cents {
+ private:
+ int m_cents{};
+
+ public:
+ explicit Cents(int cents = 0) : m_cents{cents} {}
+
+ // note that there is a space between operator keyword and the type we are casting
+ // overloading explicit cast operator
+ explicit operator int() const {
+ std::cout << "explicit operator int() const\n";
+ return m_cents;
+ }
+
+ int getCents() const { return m_cents; }
+ void setCents(int cents) { m_cents = cents; }
+};
+
+class Dollars {
+ private:
+ int m_dollars{};
+
+ public:
+ // overloading non-explicit cast operator
+ operator Cents() const {
+ std::cout << "operator Cents() const\n";
+ return Cents{m_dollars * 1000};
+ }
+
+ explicit Dollars(int dollars = 0) : m_dollars{dollars} {}
+};
+
+void printCents(Cents c) {
+ // we are using explicit for the overloading operator int()
+ std::cout << static_cast(c);
+}
+
+void run() {
+ Dollars d{100};
+ printCents(d); // Dollars -> Cents
+}
+} // namespace
+
+class TypeCast : public IExample {
+ public:
+ std::string group() const override { return "core/overloading"; }
+ std::string name() const override { return "TypeCast"; }
+ std::string description() const override { return ""; }
+
+ void execute() override { run(); }
+};
+
+REGISTER_EXAMPLE(TypeCast, "core/overloading", "TypeCast");
\ No newline at end of file
diff --git a/src/core/overloading/UnaryOperator.cpp b/src/core/overloading/UnaryOperator.cpp
new file mode 100644
index 0000000..4321586
--- /dev/null
+++ b/src/core/overloading/UnaryOperator.cpp
@@ -0,0 +1,41 @@
+// cppcheck-suppress-file[]
+
+// - + ! (-2, +3)
+#include
+#include "ExampleRegistry.h"
+
+namespace {
+class Cents {
+ private:
+ int m_cents{};
+
+ public:
+ explicit Cents(int cents) : m_cents{cents} {}
+ int getCents() const { return m_cents; }
+
+ Cents operator-() const { return Cents{-m_cents}; }
+
+ Cents operator+() const { return Cents{m_cents}; }
+
+ bool operator!() const { return m_cents == 0; }
+};
+
+void run() {
+ Cents c1{25};
+ if (!c1 == false) {
+ c1 = -c1;
+ std::cout << c1.getCents();
+ }
+}
+} // namespace
+
+class UnaryOperator : public IExample {
+ public:
+ std::string group() const override { return "core/overloading"; }
+ std::string name() const override { return "UnaryOperator"; }
+ std::string description() const override { return ""; }
+
+ void execute() override { run(); }
+};
+
+REGISTER_EXAMPLE(UnaryOperator, "core/overloading", "UnaryOperator");
\ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
index ad8b908..ff9783b 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -45,12 +45,12 @@ void runMenu() {
for (const auto& group : groups) {
std::cout << gIndex++ << ". " << group << "\n";
}
- std::cout << "0. Exit\n";
+ std::cout << gIndex << ". Exit\n";
std::cout << "----------------------------------------\n";
std::cout << "Enter choice: ";
int gChoice = readChoice();
- if (gChoice == 0) {
+ if (gChoice == gIndex) {
std::cout << "\n--- Exit ---\n";
break;
}
@@ -72,16 +72,16 @@ void runMenu() {
std::cout << eIndex++ << ". " << name << "\n";
names.push_back(name);
}
- std::cout << "0. Back\n";
+ std::cout << eIndex << ". Back\n";
std::cout << "----------------------------------------\n";
std::cout << "Enter choice: ";
int eChoice = readChoice();
- if (eChoice == 0) {
+ if (eChoice == eIndex) {
continue;
}
- if (eChoice < 1 || eChoice > names.size()) {
+ if (eChoice < 1 || eChoice > eIndex) {
std::cout << "Invalid example choice\n";
continue;
}