From 14aee0ac58f0e274f02916bb0045c7d4aefc5eca Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Tue, 24 Feb 2026 13:28:10 +0700 Subject: [PATCH 1/6] improve index exit code --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index ad8b908..af66946 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -45,7 +45,7 @@ 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: "; @@ -72,7 +72,7 @@ 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: "; From 147a7109ad6bad88874ec2a4fd07d5e4a295a01f Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Tue, 24 Feb 2026 16:26:52 +0700 Subject: [PATCH 2/6] Add document for embedded c --- src/cembedded/README.md | 325 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 325 insertions(+) create mode 100644 src/cembedded/README.md 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" From 8d88f119bea79612681a0f91951f6aee1beff3de Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Thu, 26 Feb 2026 10:21:14 +0700 Subject: [PATCH 3/6] fix menu bugs --- src/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index af66946..ff9783b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -50,7 +50,7 @@ void runMenu() { std::cout << "Enter choice: "; int gChoice = readChoice(); - if (gChoice == 0) { + if (gChoice == gIndex) { std::cout << "\n--- Exit ---\n"; break; } @@ -77,11 +77,11 @@ void runMenu() { 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; } From 797f064e0e3e19fcf3ba25f73147015137c9a65e Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Thu, 26 Feb 2026 10:38:43 +0700 Subject: [PATCH 4/6] friend keyword --- CMakeLists.txt | 2 + src/core/datatypes/class/Friend.cpp | 124 ++++++++++++++++++++++++++++ src/core/datatypes/class/README.md | 16 ++++ 3 files changed, 142 insertions(+) create mode 100644 src/core/datatypes/class/Friend.cpp create mode 100644 src/core/datatypes/class/README.md diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d4692d..1592f80 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" 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..0ed0411 --- /dev/null +++ b/src/core/datatypes/class/README.md @@ -0,0 +1,16 @@ +## 1. Friend +### 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 Function +- 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 From cbcdddebd05208b203fff1819de82f8c2a8d0d36 Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Thu, 26 Feb 2026 14:38:08 +0700 Subject: [PATCH 5/6] Add Overloading Examples --- CMakeLists.txt | 12 +++ src/core/datatypes/class/README.md | 4 +- src/core/overloading/AllocationOperator.cpp | 99 +++++++++++++++++++ src/core/overloading/ArithmeticOperator.cpp | 82 +++++++++++++++ src/core/overloading/AssignmentOperator.cpp | 51 ++++++++++ .../overloading/ClassMemberAccessOperator.cpp | 65 ++++++++++++ src/core/overloading/ComparisonOperator.cpp | 47 +++++++++ src/core/overloading/IOOperator.cpp | 64 ++++++++++++ src/core/overloading/InDecOperator.cpp | 66 +++++++++++++ src/core/overloading/ParenthesisOperator.cpp | 50 ++++++++++ src/core/overloading/SubscriptOperator.cpp | 44 +++++++++ src/core/overloading/TypeCast.cpp | 61 ++++++++++++ src/core/overloading/UnaryOperator.cpp | 41 ++++++++ 13 files changed, 685 insertions(+), 1 deletion(-) create mode 100644 src/core/overloading/AllocationOperator.cpp create mode 100644 src/core/overloading/ArithmeticOperator.cpp create mode 100644 src/core/overloading/AssignmentOperator.cpp create mode 100644 src/core/overloading/ClassMemberAccessOperator.cpp create mode 100644 src/core/overloading/ComparisonOperator.cpp create mode 100644 src/core/overloading/IOOperator.cpp create mode 100644 src/core/overloading/InDecOperator.cpp create mode 100644 src/core/overloading/ParenthesisOperator.cpp create mode 100644 src/core/overloading/SubscriptOperator.cpp create mode 100644 src/core/overloading/TypeCast.cpp create mode 100644 src/core/overloading/UnaryOperator.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1592f80..4e32591 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -154,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/core/datatypes/class/README.md b/src/core/datatypes/class/README.md index 0ed0411..6e7c99b 100644 --- a/src/core/datatypes/class/README.md +++ b/src/core/datatypes/class/README.md @@ -1,4 +1,6 @@ ## 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: @@ -9,7 +11,7 @@ X OP Y operator OP (type_of_X, type_of_Y) ``` -### 1.2. Member Function +### 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 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 From a82730ce5c2fee9208d9d23bab01440a76fcc41e Mon Sep 17 00:00:00 2001 From: Phong Nguyen Date: Thu, 26 Feb 2026 14:38:08 +0700 Subject: [PATCH 6/6] Update --- src/core/datatypes/class/CConstructors.cpp | 58 ++++++++++++---------- src/core/datatypes/class/CDestructors.cpp | 14 +++--- 2 files changed, 38 insertions(+), 34 deletions(-) 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");