### Introduction to C++ C++ is a powerful, high-performance, object-oriented programming language. It is an extension of C, adding features like classes, objects, and templates. #### Key Features: - **Object-Oriented:** Supports classes, objects, inheritance, polymorphism, abstraction, and encapsulation. - **Performance:** Close to hardware, allowing for highly optimized code. - **Memory Management:** Allows direct memory manipulation using pointers. - **Standard Library:** Rich set of libraries for various tasks. - **Portability:** Code can often be compiled and run on different platforms. ### Basic Program Structure A typical C++ program includes header files, a main function, and statements. ```cpp #include // Header file for input/output operations // The main function where program execution begins int main() { // Output a message to the console std::cout `: Preprocessor directive to include the iostream library. - `int main()`: The entry point of every C++ program. - `std::cout`: Standard output stream. - `std::endl`: Inserts a newline character and flushes the buffer. - `return 0;`: Indicates successful program termination. ### Data Types C++ has several fundamental data types to store different kinds of values. #### Primitive Data Types: - **`int`**: Integers (e.g., `10`, `-5`). Typically 4 bytes. - **`char`**: Single characters (e.g., `'a'`, `'B'`). Typically 1 byte. - **`bool`**: Boolean values (`true` or `false`). Typically 1 byte. - **`float`**: Single-precision floating-point numbers (e.g., `3.14f`). Typically 4 bytes. - **`double`**: Double-precision floating-point numbers (e.g., `3.14159`). Typically 8 bytes. - **`void`**: Represents the absence of type. Used for generic pointers or function return types. #### Type Modifiers: - `short`: Reduces storage size (e.g., `short int`). - `long`: Increases storage size (e.g., `long int`, `long double`). - `signed`: Can store both positive and negative values (default for `int`, `char`). - `unsigned`: Stores only non-negative values (e.g., `unsigned int`). #### Example: ```cpp int age = 30; char initial = 'J'; bool isStudent = true; float pi_float = 3.14f; double pi_double = 3.1415926535; unsigned int count = 100; long long bigNumber = 123456789012345LL; ``` ### Variables and Constants #### Variables: - **Declaration:** `type variableName;` - **Initialization:** `type variableName = value;` or `type variableName{value};` (C++11 uniform initialization) - **Assignment:** `variableName = newValue;` ```cpp int score; // Declaration score = 100; // Assignment double price = 9.99; // Declaration and initialization std::string name{"Alice"}; // C++11 uniform initialization ``` #### Constants: Values that cannot be changed after initialization. - **`const` keyword:** `const type variableName = value;` - **`#define` preprocessor directive:** `#define CONSTANT_NAME value` (older, less type-safe) - **`enum` keyword:** For a set of named integer constants. ```cpp const double PI = 3.14159; // Compile-time constant #define MAX_SIZE 100 // Preprocessor constant (no type checking) enum Color { RED, GREEN, BLUE }; // RED=0, GREEN=1, BLUE=2 Color myColor = GREEN; ``` ### Operators Operators perform operations on variables and values. #### Arithmetic Operators: - `+` (Addition) - `-` (Subtraction) - `*` (Multiplication) - `/` (Division) - `%` (Modulo - remainder of division) - `++` (Increment - `x++` post, `++x` pre) - `--` (Decrement - `x--` post, `--x` pre) #### Relational Operators: - `==` (Equal to) - `!=` (Not equal to) - `>` (Greater than) - ` =` (Greater than or equal to) - ` >` (Right Shift) #### Other Operators: - `sizeof` (Returns the size of a variable or type) - `?:` (Ternary/Conditional operator) - `*` (Pointer dereference) - `&` (Address-of operator) - `::` (Scope resolution operator) - `.` (Member access operator) - `->` (Member access operator for pointers) #### Operator Precedence: Determines the order in which operators are evaluated. Parentheses `()` can be used to override precedence. ### Input/Output (I/O) C++ uses streams for I/O operations, primarily `iostream`. #### Standard I/O Objects: - `std::cout`: Standard output stream (console). - `std::cin`: Standard input stream (keyboard). - `std::cerr`: Standard error stream (unbuffered output, console). - `std::clog`: Standard log stream (buffered output, console). #### Output using `std::cout`: - Uses the insertion operator ` >`. - Reads input until whitespace is encountered. - Can chain multiple inputs. ```cpp int age; std::string name; std::cout > name; // Reads "John" from "John Doe", " Doe" remains in buffer std::cout > age; std::cout > std::getline(std::cin, full_name); std::cout `): - `std::fixed`: Use fixed-point notation. - `std::scientific`: Use scientific notation. - `std::setprecision(n)`: Sets decimal precision (for floats/doubles). - `std::setw(n)`: Sets field width for next output. - `std::left`, `std::right`: Justify output. ```cpp #include // Required for manipulators double value = 123.456789; std::cout ### Control Structures Control structures dictate the flow of execution in a program. #### Conditional Statements: ##### `if`, `else if`, `else`: Executes code blocks based on conditions. ```cpp int num = 10; if (num > 0) { std::cout ### Functions Functions are blocks of code that perform a specific task. They promote modularity and code reusability. #### Function Declaration (Prototype): Specifies the function's return type, name, and parameters. Usually placed before `main()`. ```cpp int add(int a, int b); // Function prototype void greet(std::string name); ``` #### Function Definition: Contains the actual code that the function executes. ```cpp int add(int a, int b) { // Function definition return a + b; } void greet(std::string name) { std::cout ### Arrays Arrays are collections of elements of the same data type, stored in contiguous memory locations. #### Declaration and Initialization: - `type arrayName[size];` - `type arrayName[size] = {value1, value2, ...};` - `type arrayName[] = {value1, value2, ...};` (size is inferred) ```cpp int numbers[5]; // Declares an array of 5 integers int scores[3] = {90, 85, 95}; // Initializes with values double prices[] = {10.5, 20.0, 30.75}; // Size inferred as 3 ``` #### Accessing Elements: - Array elements are accessed using an index, starting from `0`. - `arrayName[index]` ```cpp numbers[0] = 10; // Assigns 10 to the first element std::cout std::vector dynamicArray; // Empty vector dynamicArray.push_back(10); // Add elements dynamicArray.push_back(20); dynamicArray.push_back(30); std::cout ### Strings C++ supports two types of strings: C-style strings (character arrays) and `std::string` (from STL). #### C-style Strings (Character Arrays): - Null-terminated arrays of characters. - Declared as `char arrayName[] = "string literal";` - Require ` ` header for string manipulation functions. ```cpp char greeting[] = "Hello"; // Automatically null-terminated char name[20]; strcpy(name, "Alice"); // Copy string strcat(greeting, ", world!"); // Concatenate int len = strlen(greeting); // Get length ``` - **Caution:** Manual memory management and buffer overflows are common issues. #### `std::string` (Standard Library Strings): - Part of the ` ` header. - More convenient, safer, and feature-rich than C-style strings. - Automatically manages memory. ##### Declaration and Initialization: ```cpp #include std::string s1; // Empty string std::string s2 = "Hello"; // Initialize with literal std::string s3("World"); // Initialize with constructor std::string s4(s2); // Copy constructor std::string s5(5, 'X'); // "XXXXX" ``` ##### Common Operations: - **Concatenation:** `+` operator or `+=` - **Length:** `.length()` or `.size()` - **Access characters:** `[]` operator or `.at()` - **Comparison:** `==`, `!=`, ` ` or `.compare()` - **Substring:** `.substr(pos, len)` - **Find:** `.find(substring)` - **Insert/Erase:** `.insert()`, `.erase()` ```cpp std::string firstName = "John"; std::string lastName = "Doe"; std::string fullName = firstName + " " + lastName; // "John Doe" std::cout ### Pointers Pointers are variables that store memory addresses. They are powerful for direct memory access and dynamic memory management. #### Declaration: - `type *pointerName;` ```cpp int* ptr; // Pointer to an integer double* dptr = nullptr; // C++11 null pointer (preferred over NULL) ``` #### Address-of Operator (`&`): Returns the memory address of a variable. ```cpp int x = 10; int* ptrX = &x; // ptrX now holds the memory address of x ``` #### Dereference Operator (`*`): Accesses the value stored at the address pointed to by the pointer. ```cpp std::cout (vptr)) ### References References are aliases (alternative names) for existing variables. Once initialized, a reference cannot be changed to refer to another variable. #### Declaration: - `type &referenceName = existingVariable;` - Must be initialized at the time of declaration. ```cpp int value = 10; int& ref = value; // ref is now an alias for value std::cout ### Dynamic Memory Allocation Allows programs to allocate memory at runtime (on the heap) instead of compile time (on the stack). #### `new` Operator: - Allocates memory for a single object or an array of objects. - Returns a pointer to the newly allocated memory. - Throws `std::bad_alloc` on failure (or returns `nullptr` if `std::nothrow` is used). ##### Single Object: ```cpp int* ptr = new int; // Allocates an int *ptr = 100; // Assign a value std::cout ` header. - Automatically call `delete` when the object goes out of scope or is no longer referenced. ##### `std::unique_ptr`: - Exclusive ownership of the dynamically allocated object. - Cannot be copied, can be moved. ```cpp #include std::unique_ptr u_ptr(new int(10)); // C++11 // Or, preferred C++14: // std::unique_ptr u_ptr = std::make_unique (10); std::cout std::shared_ptr s_ptr1(new int(20)); // C++11 // Or, preferred C++11: // std::shared_ptr s_ptr1 = std::make_shared (20); std::shared_ptr s_ptr2 = s_ptr1; // s_ptr1 and s_ptr2 share ownership std::cout ### Structs Structs (structures) are user-defined data types that group together variables of different data types under a single name. #### Declaration: - `struct StructName { member1; member2; ... };` - By default, members are `public`. ```cpp struct Point { int x; int y; }; struct Person { std::string name; int age; double height; }; ``` #### Creating Objects (Variables): ```cpp Point p1; // Declares a Point variable p1.x = 10; p1.y = 20; Person person1 = {"Alice", 30, 1.65}; // C++11 aggregate initialization Person person2; person2.name = "Bob"; person2.age = 25; person2.height = 1.80; ``` #### Accessing Members: - Use the dot operator (`.`) for direct access. - Use the arrow operator (`->`) for pointers to structs. ```cpp std::cout name ### Classes and Objects Classes are blueprints for creating objects. Objects are instances of classes. C++ is an object-oriented programming language, and classes are its core. #### Class Declaration: - Defines data members (attributes) and member functions (methods). - `class ClassName { access_specifiers: members; };` ```cpp class Car { public: // Access specifier: members are accessible from outside the class std::string brand; std::string model; int year; // Member function (method) void displayInfo() { std::cout brand = "Honda"; anotherCar->model = "Civic"; anotherCar->year = 2022; anotherCar->displayInfo(); delete anotherCar; // Remember to delete heap-allocated objects ``` #### Constructors: - Special member functions called automatically when an object is created. - Used to initialize object's data members. - Has the same name as the class and no return type. ##### Default Constructor: - No parameters. If no constructor is defined, the compiler provides a default one. ```cpp class Dog { public: std::string name; int age; Dog() { // Default constructor name = "Unknown"; age = 0; std::cout ### `this` Pointer - A keyword in C++ that refers to the current object. - It is an implicit pointer to the object on which a member function is called. - Is a `const` pointer, meaning you cannot change what `this` points to. #### Use Cases: 1. **Distinguishing between data members and local variables/parameters:** ```cpp class Box { public: double length; void setLength(double length) { this->length = length; // 'this->length' refers to the member variable // 'length' refers to the parameter } }; ``` 2. **Returning the current object from a member function:** - Useful for method chaining. ```cpp class Calculator { int value; public: Calculator(int v = 0) : value(v) {} Calculator& add(int num) { this->value += num; return *this; // Return reference to the current object } Calculator& subtract(int num) { this->value -= num; return *this; } int getResult() const { return value; } }; int main() { Calculator calc(10); int result = calc.add(5).subtract(2).getResult(); // Chaining calls std::cout ### Copy Constructor - A special constructor that creates a new object as a copy of an existing object. - Automatically called when: - An object is initialized with another object of the same type. - An object is passed by value to a function. - An object is returned by value from a function. #### Syntax: `ClassName(const ClassName& obj);` #### Default Copy Constructor: - If you don't define one, the compiler provides a default copy constructor. - Performs a **shallow copy** (member-wise copy). This is fine if your class only contains primitive data types or smart pointers. - **Problem:** If your class manages raw pointers (dynamically allocated memory), a shallow copy leads to two objects pointing to the same memory, causing issues on destruction (double-free) or incorrect modifications. #### User-Defined Copy Constructor (Deep Copy): - Necessary when your class manages resources (e.g., dynamically allocated memory, file handles). - Performs a **deep copy**, allocating new resources for the new object and copying the contents. ```cpp class MyArray { public: int* data; int size; MyArray(int s) : size(s) { // Constructor data = new int[size]; std::cout ### Copy Assignment Operator (`=`) - A special member function used to assign one existing object to another existing object of the same type. - Called when an assignment (`=`) occurs between two already constructed objects. #### Syntax: `ClassName& operator=(const ClassName& other);` #### Default Copy Assignment Operator: - Performs a shallow, member-wise copy. - Similar to the copy constructor, this leads to issues with raw pointers/dynamically allocated memory. #### User-Defined Copy Assignment Operator (Deep Copy): - Required for classes managing raw resources. - Steps: 1. Handle self-assignment (`this == &other`) to prevent self-destruction. 2. Deallocate any resources currently held by the target object. 3. Allocate new resources if necessary. 4. Copy data from the source object. 5. Return `*this` by reference. ```cpp class MyArray { public: int* data; int size; MyArray(int s) : size(s) { data = new int[size]; } MyArray(const MyArray& other) : size(other.size) { // Copy Constructor data = new int[size]; for (int i = 0; i ### Move Semantics (C++11) - Introduced to improve performance by allowing resources (like dynamically allocated memory) to be *moved* from one object to another, rather than copied, when the source object is a temporary (rvalue) and will soon be destroyed. - Prevents unnecessary deep copies. - Uses **rvalue references** (`&&`). #### Rvalue References (`&&`): - References that bind to rvalues (temporary objects, literals, results of expressions). - Allow you to distinguish between lvalues (objects that have a name and persist beyond the expression) and rvalues. #### Move Constructor: - `ClassName(ClassName&& other);` - Takes an rvalue reference to another object. - "Steals" the resources from the source object. - Leaves the source object in a valid, but unspecified, state (typically "empty" or "null"). #### Move Assignment Operator: - `ClassName& operator=(ClassName&& other);` - Similar to move constructor, but for assignment between existing objects. ```cpp class MyArray { public: int* data; int size; MyArray(int s) : size(s) { data = new int[size]; for (int i = 0; i ### Inheritance - A mechanism where one class (derived class/subclass) inherits properties and behaviors from another class (base class/superclass). - Promotes code reusability and establishes an "is-a" relationship. #### Syntax: `class DerivedClass : access_specifier BaseClass { ... };` #### Access Specifiers for Inheritance: - **`public` inheritance:** - `public` members of base class become `public` in derived. - `protected` members of base class become `protected` in derived. - `private` members of base class remain `private` (not accessible directly). - Models the "is-a" relationship (e.g., `Car` is a `Vehicle`). This is the most common form. - **`protected` inheritance:** - `public` and `protected` members of base class become `protected` in derived. - **`private` inheritance:** - `public` and `protected` members of base class become `private` in derived. - Models a "has-a" or "implemented-in-terms-of" relationship (less common). #### Example: Public Inheritance ```cpp class Vehicle { // Base class public: std::string brand = "Ford"; void honk() { std::cout Derived class constructor. - **Destruction:** Derived class destructor -> Base class destructor. #### Multiple Inheritance: - A class can inherit from multiple base classes. - `class Derived : public Base1, public Base2 { ... };` - Can lead to the "diamond problem" (ambiguity if both base classes share a common ancestor and derived class inherits it twice). Solved using `virtual` inheritance. ### Polymorphism - The ability of objects of different classes to respond to the same message (function call) in different ways. - Achieved through **virtual functions** and **pointers/references to base class objects**. #### Virtual Functions: - A member function declared with the `virtual` keyword in the base class. - Allows the derived class's implementation of the function to be called, even when accessed through a base class pointer or reference (runtime polymorphism). ```cpp class Animal { public: virtual void makeSound() { // Virtual function std::cout makeSound(); // Output: Animal makes a sound myDog->makeSound(); // Output: Woof! (runtime polymorphism) myCat->makeSound(); // Output: Meow! delete myAnimal; // Animal destructor delete myDog; // Dog destructor, then Animal destructor (due to virtual destructor) delete myCat; // Cat destructor, then Animal destructor return 0; } ``` #### Virtual Destructors: - **Crucial** when dealing with polymorphism. - If a base class pointer points to a derived class object and you `delete` the base pointer, a non-virtual destructor will only call the base class's destructor, leading to a memory leak for derived class resources. - A `virtual` destructor ensures that the correct derived class destructor is called, followed by the base class destructor. #### Pure Virtual Functions and Abstract Classes: - A pure virtual function is declared by assigning `0` to it in the base class: `virtual void func() = 0;` - A class containing at least one pure virtual function is an **abstract class**. - Abstract classes cannot be instantiated directly; they must be inherited from. - Derived classes **must** implement all pure virtual functions (unless they too are abstract). - Used to define an interface or a contract that derived classes must adhere to. ```cpp class Shape { // Abstract Base Class public: virtual double area() = 0; // Pure virtual function virtual void draw() = 0; // Pure virtual function virtual ~Shape() {} // Virtual destructor for proper cleanup }; class Circle : public Shape { public: double radius; Circle(double r) : radius(r) {} double area() override { return 3.14159 * radius * radius; } void draw() override { std::cout area() draw(); std::cout area() draw(); delete s1; delete s2; return 0; } ``` ### Templates - Allow you to write generic code that works with different data types without rewriting the code for each type. - Promote code reusability and type safety. #### Function Templates: - Define a generic function that can operate on different data types. ```cpp template // or template T add(T a, T b) { return a + b; } int main() { std::cout class MyPair { public: T first; T second; MyPair(T a, T b) : first(a), second(b) {} void print() { std::cout p1(10, 20); // MyPair for int p1.print(); // Output: (10, 20) MyPair p2(3.14, 2.71); // MyPair for double p2.print(); // Output: (3.14, 2.71) MyPair p3("Apple", "Banana"); // MyPair for std::string p3.print(); // Output: (Apple, Banana) return 0; } ``` #### Non-Type Template Parameters: - Templates can also take non-type parameters, such as integral values. ```cpp template // N is a non-type parameter class MyStaticArray { public: T arr[N]; // Array of size N void fill(T val) { for (int i = 0; i intArr; // Array of 5 ints intArr.fill(10); intArr.print(); // Output: 10 10 10 10 10 MyStaticArray doubleArr; // Array of 3 doubles doubleArr.fill(2.5); doubleArr.print(); // Output: 2.5 2.5 2.5 return 0; } ``` #### Template Specialization: - Allows you to provide a specific implementation for a particular type or set of types, overriding the generic template. ```cpp // Generic template template void process(T val) { std::cout void process (int val) { std::cout ### Exception Handling - A mechanism to deal with runtime errors or exceptional conditions in a structured way. - Uses `try`, `catch`, and `throw` keywords. #### `try` Block: - Encloses the code that might throw an exception. #### `throw` Statement: - Used to signal an exceptional condition. - Can throw any type (e.g., `int`, `std::string`, custom exception objects). #### `catch` Block: - Catches exceptions thrown by the `try` block. - Can have multiple `catch` blocks to handle different exception types. - `catch (...)` can catch any type of exception (the ellipsis `...` acts as a wildcard). ```cpp #include #include #include // For standard exception types double divide(double numerator, double denominator) { if (denominator == 0) { throw std::runtime_error("Division by zero error!"); // Throw a standard exception object } return numerator / denominator; } int main() { try { double result1 = divide(10, 2); std::cout // For std::exception class MyCustomException : public std::runtime_error { public: MyCustomException(const std::string& msg) : std::runtime_error("MyCustomException: " + msg) {} }; void checkValue(int val) { if (val 100) { throw MyCustomException("Value exceeds limit!"); } std::cout ### File Input/Output (File I/O) - Used to read from and write to files. - Requires the ` ` header. #### File Streams: - `std::ofstream`: Output file stream (for writing). - `std::ifstream`: Input file stream (for reading). - `std::fstream`: General file stream (for both reading and writing). #### Opening a File: - **Constructor:** `std::ofstream outfile("filename.txt");` - **`open()` method:** `outfile.open("filename.txt", std::ios::app);` ##### File Open Modes (`std::ios::openmode`): - `std::ios::in`: Open for reading (default for `ifstream`). - `std::ios::out`: Open for writing (default for `ofstream`). - `std::ios::app`: Append to end of file. - `std::ios::trunc`: Truncate file to zero length if it exists (default for `ofstream`). - `std::ios::ate`: Seek to end of file immediately after opening. - `std::ios::binary`: Open in binary mode. #### Checking if File is Open: - `if (fileStream.is_open())` or `if (fileStream)` #### Writing to a File: - Use ` #include #include int main() { std::ofstream outFile("example.txt"); // Opens file for writing (truncates if exists) if (outFile.is_open()) { outFile >` operator (like `std::cin`) for word-by-word or tokenized input. - Use `std::getline()` for line-by-line input. ```cpp #include #include #include int main() { std::ifstream inFile("example.txt"); // Opens file for reading if (inFile.is_open()) { std::string line; std::cout ### STL Containers - Standard Template Library (STL) provides generic, reusable data structures (containers) and algorithms. - Containers are classes that manage collections of objects. #### Sequence Containers: Store elements in a linear fashion, allowing access by position. 1. **`std::vector` (Dynamic Array):** - Header: ` ` - Resizable array, elements stored contiguously. - Fast random access (`O(1)`). - Fast insertion/deletion at the end (`O(1)` amortized). - Slow insertion/deletion in the middle (`O(N)`). ```cpp #include std::vector v = {1, 2, 3}; v.push_back(4); // {1, 2, 3, 4} v.insert(v.begin() + 1, 99); // {1, 99, 2, 3, 4} v.pop_back(); // {1, 99, 2, 3} std::cout ` - Dynamic array that supports efficient insertion/deletion at both ends (`O(1)`). - Fast random access (`O(1)`). - Elements are not necessarily contiguous. ```cpp #include std::deque d = {1, 2, 3}; d.push_front(0); // {0, 1, 2, 3} d.push_back(4); // {0, 1, 2, 3, 4} d.pop_front(); // {1, 2, 3, 4} ``` 3. **`std::list` (Doubly Linked List):** - Header: ` ` - Elements are not stored contiguously. - Fast insertion/deletion anywhere (`O(1)`). - Slow random access (`O(N)`). ```cpp #include std::list l = {1, 2, 3}; l.push_front(0); // {0, 1, 2, 3} l.insert(++l.begin(), 99); // {0, 99, 1, 2, 3} (Iterator arithmetic is limited) ``` 4. **`std::forward_list` (Singly Linked List - C++11):** - Header: ` ` - More memory efficient than `std::list` but only supports forward iteration. #### Container Adapters: Provide a restricted interface to an underlying container. 1. **`std::stack` (LIFO - Last-In, First-Out):** - Header: ` ` - Uses `push()`, `pop()`, `top()`. - By default, uses `std::deque` as underlying container. ```cpp #include std::stack s; s.push(10); s.push(20); std::cout ` - Uses `push()`, `pop()`, `front()`, `back()`. - By default, uses `std::deque` as underlying container. ```cpp #include std::queue q; q.push(10); q.push(20); std::cout ` - Elements are ordered by value (largest at top by default). - Uses `push()`, `pop()`, `top()`. - By default, uses `std::vector` and `std::less` (max-heap). ```cpp #include std::priority_queue pq; pq.push(30); pq.push(10); pq.push(20); std::cout ` - Stores elements in key-sorted order. - Unique keys. - Logarithmic time complexity (`O(logN)`) for insertion, deletion, lookup. ```cpp #include std::map ages; ages["Alice"] = 30; ages["Bob"] = 25; ages.insert({"Charlie", 35}); std::cout ` - Stores unique elements in sorted order. - Logarithmic time complexity (`O(logN)`). ```cpp #include std::set uniqueNumbers = {5, 2, 8, 2, 5}; uniqueNumbers.insert(10); // {2, 5, 8, 10} for (int n : uniqueNumbers) { std::cout ` - Key-value pairs, average `O(1)` lookup. - No guaranteed order. ```cpp #include std::unordered_map userScores; userScores["John"] = 100; userScores["Jane"] = 150; std::cout ` - Unique elements, average `O(1)` lookup. - No guaranteed order. ```cpp #include std::unordered_set fastSet = {7, 1, 9, 1, 7}; fastSet.insert(3); // {9, 7, 3, 1} (order may vary) ``` ### STL Algorithms - Standard Template Library (STL) provides a rich set of generic algorithms that operate on ranges of elements. - Algorithms typically work with iterators, making them container-agnostic. - Header: ` ` and ` ` for some math algorithms. #### Common Algorithms: 1. **`std::sort`:** Sorts elements in a range. - `std::sort(begin_iterator, end_iterator);` - `std::sort(begin_iterator, end_iterator, custom_comparator);` ```cpp #include #include #include std::vector v = {5, 2, 8, 1, 9}; std::sort(v.begin(), v.end()); // v becomes {1, 2, 5, 8, 9} // Custom sort (descending) std::sort(v.begin(), v.end(), [](int a, int b){ return a > b; }); // v becomes {9, 8, 5, 2, 1} ``` 2. **`std::find`:** Searches for a specific value in a range. - Returns an iterator to the first occurrence or `end_iterator` if not found. ```cpp auto it = std::find(v.begin(), v.end(), 5); if (it != v.end()) { std::cout `):** Calculates the sum of elements in a range. ```cpp #include int sum = std::accumulate(v.begin(), v.end(), 0); // 0 is initial sum std::cout v_orig = {1, 2, 3, 4}; std::vector v_squared(v_orig.size()); std::transform(v_orig.begin(), v_orig.end(), v_squared.begin(), [](int n){ return n * n; }); // v_squared: {1, 4, 9, 16} ``` 8. **`std::copy`:** Copies elements from one range to another. ```cpp std::vector source = {1, 2, 3}; std::vector dest(3); std::copy(source.begin(), source.end(), dest.begin()); // dest: {1, 2, 3} ``` #### Iterators: - Generic pointers that allow algorithms to work with different container types. - Common iterator types: - `begin()`: Returns an iterator to the first element. - `end()`: Returns an iterator to one past the last element. - `cbegin()`, `cend()`: Constant iterators (cannot modify elements). - `rbegin()`, `rend()`: Reverse iterators. #### Lambdas (C++11): - Anonymous functions that can be defined inline. - Often used with STL algorithms for custom operations. - Syntax: `[captures](parameters) -> return_type { body }` - `captures`: Variables from the enclosing scope. - `[]`: No capture. - `[var]`: Capture `var` by value. - `[&var]`: Capture `var` by reference. - `[=]`: Capture all local variables by value. - `[&]`: Capture all local variables by reference. ```cpp int x = 10; auto myLambda = [x](int y) { return x + y; }; // Captures x by value std::cout ### Smart Pointers (Advanced) - Introduced in C++11, smart pointers are objects that behave like pointers but also manage the memory of the object they point to. - They automatically call `delete` when the object is no longer needed, preventing memory leaks and simplifying resource management (RAII - Resource Acquisition Is Initialization). - Header: ` ` #### 1. `std::unique_ptr`: - **Exclusive ownership:** Only one `unique_ptr` can own a resource at a time. - Cannot be copied, but can be **moved** (ownership is transferred). - Automatically deallocates memory when it goes out of scope. - Lightweight and efficient. ```cpp #include #include class MyObject { public: MyObject() { std::cout ptr1 = std::make_unique (); ptr1->greet(); // Ownership transfer (move) std::unique_ptr ptr2 = std::move(ptr1); ptr2->greet(); // ptr1 is now null, trying to use it is undefined behavior if (!ptr1) { std::cout ptr3(new MyObject()); // When main ends, any remaining unique_ptr objects will be destructed, // and their managed memory will be freed. return 0; } ``` #### 2. `std::shared_ptr`: - **Shared ownership:** Multiple `shared_ptr` objects can own the same resource. - Uses a **reference count** to track how many `shared_ptr`s point to the resource. - Memory is deallocated when the last `shared_ptr` owning the resource is destroyed or reset. - Slightly heavier than `unique_ptr` due to managing the reference count. ```cpp #include #include int main() { // Creation (C++11 preferred with make_shared) std::shared_ptr s_ptr1 = std::make_shared (); s_ptr1->greet(); std::cout s_ptr2 = s_ptr1; std::cout s_ptr3 = s_ptr1; std::cout #include class B; // Forward declaration class A { public: std::shared_ptr b_ptr; // A owns B A() { std::cout a_ptr; // B observes A (does not own A) B() { std::cout a = std::make_shared (); // Ref count A: 1 std::shared_ptr b = std::make_shared (); // Ref count B: 1 a->b_ptr = b; // A now owns B. Ref count B: 2 b->a_ptr = a; // B observes A. Ref count A: 1 (weak_ptr doesn't increase count) // Without weak_ptr for a_ptr, if it was shared_ptr , // we would have a->b_ptr (owns B) and b->a_ptr (owns A), leading to a circular reference. // Both A and B would have a ref count of 2, never reaching 0, causing a leak. // Accessing A from B: if (auto sharedA = b->a_ptr.lock()) { // lock() returns a shared_ptr if object exists std::cout b_ptr). b is destructed. // Ref count A drops to 0. a is destructed. return 0; } ``` ### Type Casting - Used to convert a value from one data type to another. - C++ offers several casting operators, each with specific use cases and safety levels. #### C-style Cast: - ` (type)expression ` - Performs a combination of `static_cast`, `const_cast`, and `reinterpret_cast`. - Dangerous as it doesn't perform compile-time checks and can easily lead to undefined behavior. **Avoid in C++.** ```cpp double d = 3.14; int i = (int)d; // C-style cast, i becomes 3 ``` #### C++ Style Casts (Preferred): Provide more specific and safer conversion mechanisms. 1. **`static_cast`:** - `static_cast (expression)` - Used for conversions that are well-defined and compile-time safe. - E.g., `int` to `float`, `base` to `derived` (downcasting, requires `dynamic_cast` for safety), `void*` to `specific_type*`. - Does not perform runtime checks for downcasting. ```cpp int i = 10; double d = static_cast (i); // int to double (safe) void* ptr = &i; int* int_ptr = static_cast (ptr); // void* to int* (safe) class Base { /* ... */ }; class Derived : public Base { /* ... */ }; Base* b_ptr = new Derived(); Derived* d_ptr = static_cast (b_ptr); // Downcast (unsafe without runtime check) // Only safe if b_ptr actually points to a Derived object ``` 2. **`dynamic_cast`:** - `dynamic_cast (expression)` - Used for safe downcasting (from base class pointer/reference to derived class pointer/reference) in polymorphic class hierarchies (classes with at least one virtual function). - Performs a **runtime check**. - If the cast is invalid: - For pointers, returns `nullptr`. - For references, throws `std::bad_cast` exception. ```cpp #include // For std::bad_cast class Base { public: virtual ~Base() {} }; // Must have virtual function class Derived : public Base {}; class OtherDerived : public Base {}; Base* b1 = new Derived(); if (Derived* d1 = dynamic_cast (b1)) { // Safe downcast std::cout (b2)) { // Fails, d2 is nullptr std::cout (*b1); // Safe reference downcast std::cout (*b1); // Throws std::bad_cast } catch (const std::bad_cast& e) { std::cerr (expression)` - Used to add or remove `const` or `volatile` qualifiers from a pointer or reference. - **Caution:** Only use to cast away `const`ness if the original object was *not* declared `const`. Modifying a truly `const` object through `const_cast` leads to undefined behavior. ```cpp const int val = 10; // int* ptr = &val; // Error: cannot convert const int* to int* int* ptr = const_cast (&val); // Cast away constness *ptr = 20; // Undefined behavior if val was truly const (e.g., int const val = 10;) // If val was int val = 10; and then passed to a function as const int&, // then casting away constness and modifying through ptr would be fine. std::cout (expression)` - Used for low-level, unsafe conversions between unrelated pointer types or between pointers and integral types. - Does not perform any type checking. - Highly platform-dependent and generally indicates a design flaw if frequently used. **Use with extreme caution.** ```cpp int i = 65; // ASCII for 'A' int* i_ptr = &i; char* c_ptr = reinterpret_cast (i_ptr); // Treats memory of int as char std::cout (i_ptr); // Pointer to integral type std::cout ### Operator Overloading - Allows you to redefine the behavior of C++ operators for user-defined types (classes/structs). - Makes code more intuitive and readable when dealing with custom objects. #### Syntax: - Member function: `ReturnType operator Symbol (parameters)` - Non-member (global) function: `ReturnType operator Symbol (parameters)` #### Operators that CAN be Overloaded: `+ - * / % ^ & | ~ ! = += -= *= /= %= ^= &= |= > >= == != = && || ++ -- , ->* -> () [] new new[] delete delete[]` #### Operators that CANNOT be Overloaded: `.` (member access), `.*` (pointer to member access), `::` (scope resolution), `?:` (ternary conditional), `sizeof` #### Example: Overloading `+` and ` class Complex { public: double real; double imag; Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {} // 1. Overloading binary '+' as a member function // Adds a Complex object to the current object Complex operator+(const Complex& other) const { return Complex(real + other.real, imag + other.imag); } // 2. Overloading unary '-' as a member function // Negates the Complex number Complex operator-() const { return Complex(-real, -imag); } // 3. Overloading '==' as a member function bool operator==(const Complex& other) const { return (real == other.real && imag == other.imag); } }; // 4. Overloading ' = 0) { os `) can be overloaded as member functions (take one parameter, the right operand) or non-member functions (take two parameters, left and right operands). - If the left operand is not an object of the class (e.g., `std::cout ` (member access operator)**: Always a member function, returns a pointer. - **`=` (assignment operator)**: Always a member function. - Maintain natural interpretation: Overload operators such that their behavior is intuitive and consistent with their standard use. - Avoid over-overloading: Don't overload operators just because you can; do it only when it makes sense semantically. ### Rvalue References (`&&`) - Introduced in C++11 to enable **move semantics** and **perfect forwarding**. - An rvalue reference is a reference that binds to an rvalue (a temporary object or expression that doesn't have a name and won't persist beyond the current expression). - Distinguished from lvalue references (`&`), which bind to lvalues (objects that have a name and persist). #### Lvalues vs. Rvalues: - **Lvalue:** An expression that refers to a memory location and has a name (e.g., `int x;`, `obj.member;`, `*ptr;`). You can take its address. - **Rvalue:** An expression that is not an lvalue; typically a temporary object, a literal, or the result of an operation (e.g., `10;`, `x + y;`, `func_returns_by_value();`). You cannot take its address directly (unless it's a string literal). ```cpp int x = 10; // x is an lvalue int y = x; // x is an lvalue int z = x + y; // (x + y) is an rvalue int& lref = x; // lvalue reference binds to lvalue // int& lref2 = x + y; // Error: lvalue reference cannot bind to rvalue const int& clref = x + y; // OK: const lvalue reference can bind to rvalue (extends lifetime) int&& rref = x + y; // OK: rvalue reference binds to rvalue // int&& rref2 = x; // Error: rvalue reference cannot bind to lvalue ``` #### Purpose of Rvalue References: 1. **Enabling Move Semantics:** - Allows resources to be "stolen" from temporary objects instead of being deep-copied. - Implemented by **move constructors** and **move assignment operators**. - Significant performance improvement for types that manage large resources (e.g., `std::vector`, `std::string`, custom classes with `new`/`delete`). ```cpp // See "Move Semantics" section for detailed example. // MyArray(MyArray&& other) noexcept; // Move Constructor // MyArray& operator=(MyArray&& other) noexcept; // Move Assignment Operator ``` 2. **Perfect Forwarding:** - Allows a function template to take arguments of any value category (lvalue or rvalue) and forward them to another function while preserving their original value category. - Achieved using `std::forward` in conjunction with universal references (template type parameters that are rvalue references, `T&&`). ```cpp #include // For std::forward void processValue(int& val) { std::cout void wrapper(T&& arg) { // arg is a "universal reference" or "forwarding reference" processValue(std::forward (arg)); // Preserves arg's value category } int main() { int a = 10; wrapper(a); // Calls processValue(int&) -> Output: Processing lvalue: 10 wrapper(20); // Calls processValue(int&&) -> Output: Processing rvalue: 20 wrapper(a + 30); // Calls processValue(int&&) -> Output: Processing rvalue: 50 return 0; } ``` #### `std::move`: - A function in ` ` that unconditionally casts its argument to an rvalue reference. - Does **not** actually move anything; it just enables the compiler to select a move constructor/assignment operator if available. - Use `std::move` when you want to explicitly indicate that an lvalue object's resources can be "stolen" because you won't use it afterwards. ```cpp std::vector v1 = {1, 2, 3}; std::vector v2 = std::move(v1); // v2 takes ownership of v1's data // v1 is now in a valid but unspecified state (e.g., empty). Do not rely on its contents. ``` ### Concurrency (C++11) - Allows parallel execution of different parts of a program, improving performance and responsiveness. - C++11 introduced standard library support for multithreading. - Header: ` `, ` `, ` `, ` ` #### 1. `std::thread`: - Represents a single thread of execution. - Created by passing a callable object (function, lambda, functor) to its constructor. ```cpp #include #include #include // For std::this_thread::sleep_for void task1() { for (int i = 0; i #include #include #include std::mutex mtx; // Global mutex int shared_data = 0; void increment_shared_data() { for (int i = 0; i guard(mtx); // Lock acquired on construction, released on destruction shared_data++; } } int main() { std::vector threads; for (int i = 0; i #include #include #include std::atomic atomic_shared_data = 0; // Atomic integer void increment_atomic_data() { for (int i = 0; i threads; for (int i = 0; i #include #include long long calculate_sum(long long limit) { long long sum = 0; for (long long i = 0; i future_result = std::async(std::launch::async, calculate_sum, 1000000000); std::cout ### Macros and Preprocessor Directives - The C++ preprocessor is a program that processes the source code before compilation. - Directives start with `#`. #### 1. `#include`: - Inserts the content of another file into the current file. - `#include `: For standard library headers (searches standard directories). - `#include "my_header.h"`: For user-defined headers (searches current directory first). #### 2. `#define`: - Defines a macro, which is a symbolic name or a piece of code that is replaced by its value before compilation. - **Object-like macros:** Simple text replacement. - **Function-like macros:** Take arguments, similar to functions. ```cpp #define PI 3.14159 // Object-like macro #define MAX(a, b) ((a) > (b) ? (a) : (b)) // Function-like macro (use parentheses for safety) int main() { double circumference = 2 * PI * 5; // PI replaced by 3.14159 int result = MAX(10, 20); // Replaced by ((10) > (20) ? (10) : (20)) std::cout = 201103L // Check C++ standard version (C++11 or later) std::cout ### Standard Library Utilities - C++ Standard Library provides many useful utilities beyond containers and algorithms. #### 1. ` `: - **`std::pair`:** A simple struct holding two heterogeneous values. ```cpp #include #include std::pair student = {"Alice", 20}; std::cout ``` - **`std::move`, `std::forward`:** See "Rvalue References" section. #### 2. ` ` (C++11): - Similar to `std::pair` but can hold an arbitrary number of heterogeneous values. ```cpp #include std::tuple person = {"Charlie", 30, 1.75}; std::cout (person) (person) (person) ` (C++11): - Provides types and functions for dealing with time durations, time points, and clocks. ```cpp #include #include // For std::this_thread::sleep_for #include int main() { auto start = std::chrono::high_resolution_clock::now(); // Get current time point // Simulate some work std::this_thread::sleep_for(std::chrono::milliseconds(100)); auto end = std::chrono::high_resolution_clock::now(); // Get current time point again std::chrono::duration duration = end - start; // Calculate duration std::cout ` (C++11): - Sophisticated random number generation facilities. - Separates random number engines (generators) from distributions. ```cpp #include #include int main() { // 1. Create a random number engine (e.g., Mersenne Twister) std::random_device rd; // Provides a non-deterministic seed std::mt19937 gen(rd()); // Seed the generator // 2. Define a distribution (e.g., uniform integer distribution) std::uniform_int_distribution<> distrib(1, 100); // Numbers between 1 and 100 (inclusive) // 3. Generate random numbers for (int i = 0; i `: - Provides numerical algorithms. - `std::accumulate`: Sums elements (see "STL Algorithms"). - `std::iota` (C++11): Fills a range with sequentially increasing values. ```cpp #include #include #include std::vector v(5); std::iota(v.begin(), v.end(), 1); // Fills v with 1, 2, 3, 4, 5 for (int x : v) { std::cout `: - Provides function objects (functors), function wrappers, and binders. - `std::function` (C++11): A general-purpose polymorphic function wrapper. Can store, copy, and invoke any callable target (function pointers, lambdas, functors, member functions). ```cpp #include #include int multiply(int a, int b) { return a * b; } int main() { std::function func1 = multiply; std::cout func2 = [](int x){ return x * x; }; std::cout ### C++ Best Practices #### 1. **Prefer `const` over `#define` for constants.** - `const` variables are type-safe and respect scope, unlike macros. - `const int MAX_SIZE = 100;` is better than `#define MAX_SIZE 100`. #### 2. **Use `std::string` over C-style character arrays.** - `std::string` handles memory management automatically, preventing buffer overflows and simplifying string operations. #### 3. **Use `std::vector` over raw arrays for dynamic collections.** - `std::vector` manages memory dynamically and provides bounds checking (with `.at()`), iterators, and many utility functions. #### 4. **Prefer Smart Pointers (`std::unique_ptr`, `std::shared_ptr`) over raw pointers for heap memory management.** - Smart pointers implement RAII, ensuring memory is automatically released, preventing memory leaks. - `std::unique_ptr` for exclusive ownership, `std::shared_ptr` for shared ownership. #### 5. **Follow the Rule of Zero/Five.** - **Rule of Zero:** If your class doesn't manage raw resources directly, you likely don't need to define a destructor, copy/move constructors, or copy/move assignment operators. The compiler-generated ones (or those of smart member objects) will suffice. This is the ideal. - **Rule of Five:** If your class *does* manage raw resources (e.g., `new`/`delete`), you probably need to define all five special member functions: destructor, copy constructor, copy assignment operator, move constructor, and move assignment operator. #### 6. **Pass objects by `const&` (constant reference) for input parameters.** - Avoids expensive copying for large objects. - Prevents modification of the original object inside the function. #### 7. **Pass objects by `&` (non-constant reference) for output parameters or when modification is intended.** - Allows the function to modify the original object efficiently. #### 8. **Prefer `const` member functions where possible.** - A `const` member function guarantees it will not modify the object's state. - Allows `const` objects to call these functions. #### 9. **Use Constructor Initializer Lists.** - More efficient for member initialization, especially for `const` members, references, or member objects that don't have default constructors. - `MyClass(int a, int b) : memberA(a), memberB(b) {}` #### 10. **Make Base Class Destructors `virtual` if derived classes will be deleted via base pointers.** - Crucial for correct polymorphic destruction and preventing memory leaks. #### 11. **Use `override` and `final` keywords (C++11).** - `override`: Explicitly indicates that a member function is overriding a virtual function in a base class. Helps catch errors at compile time if the signature doesn't match. - `final`: Prevents a virtual function from being overridden in derived classes, or prevents a class from being inherited. #### 12. **Prefer `enum class` (scoped enums - C++11) over `enum` (unscoped enums).** - `enum class` prevents name clashes and provides type safety. ```cpp enum class Color { Red, Green, Blue }; // Color c = Red; // Error Color c = Color::Red; // OK // int x = Color::Red; // Error: no implicit conversion ``` #### 13. **Avoid C-style casts; use C++-style casts (`static_cast`, `dynamic_cast`, `const_cast`, `reinterpret_cast`).** - C++ casts are more specific, safer, and easier to search for in code. #### 14. **Use `nullptr` (C++11) instead of `NULL` or `0` for null pointers.** - `nullptr` is type-safe and avoids ambiguity. #### 15. **Embrace RAII (Resource Acquisition Is Initialization).** - Manage resources (memory, file handles, locks) using objects that acquire the resource in their constructor and release it in their destructor. Smart pointers and `std::lock_guard` are prime examples. #### 16. **Handle exceptions gracefully.** - Use `try-catch` blocks for error handling where appropriate, especially for operations that might fail (e.g., file I/O, network communication, dynamic memory allocation). #### 17. **Use `const` for variables that should not change.** - Improves readability and allows the compiler to perform optimizations and catch accidental modifications. #### 18. **Prefer `for (auto& item : container)` for iterating over collections where modification is needed, and `for (const auto& item : container)` for read-only iteration.** - More concise and less error-prone than traditional index-based or iterator-based loops. #### 19. **Organize code into header (`.h`/`.hpp`) and source (`.cpp`) files.** - Header files declare classes, functions, and global variables. - Source files define the implementations. - Use header guards to prevent multiple inclusions. #### 20. **Use `std::vector::emplace_back` or `std::map::emplace` instead of `push_back`/`insert` when possible.** - `emplace` functions construct objects in-place directly within the container, avoiding temporary object creation and moving/copying, which can be more efficient.