C
h
i
L
L
u
.
.
.

C++ Programming Mastery Guide

Complete guide from OOP basics to modern C++ features

Understanding C++: Power and Performance

C++ is a powerful, high-performance programming language created by Bjarne Stroustrup as an extension of C. It combines low-level memory manipulation with high-level object-oriented features, making it ideal for system software, game development, high-frequency trading, and performance-critical applications.

What makes C++ unique is its "zero-cost abstractions" philosophy - you don't pay for features you don't use. Modern C++ (C++11 and beyond) introduces powerful features like smart pointers, lambda expressions, and move semantics while maintaining backward compatibility.

Industry Powerhouse: C++ powers major software like Google Chrome, Microsoft Windows, Adobe Creative Suite, Unreal Engine, and MySQL. Its performance makes it the language of choice for applications where speed and efficiency are critical.

1. C++ Basics & OOP Fundamentals

Hello World: Your First C++ Program

C++ programs use streams for input/output and follow similar structure to C, but with additional features like namespaces and object-oriented capabilities.
// hello.cpp
#include <iostream>  // Input/output stream
#include <string>    // String class

using namespace std; // Use standard namespace

int main() {
    cout << "Hello, World!" << endl;
    cout << "Welcome to C++ Programming!" << endl;
    
    // String manipulation
    string name = "Alice";
    cout << "Hello, " << name << "!" << endl;
    
    // Input from user
    int age;
    cout << "Enter your age: ";
    cin >> age;
    cout << "You are " << age << " years old." << endl;
    
    return 0;
}

// Compile and run:
// g++ hello.cpp -o hello
// ./hello

C++ Enhancements Over C

C++ provides several improvements over C including references, function overloading, default parameters, and the bool data type.
#include <iostream>
using namespace std;

// Function overloading - same name, different parameters
void print(int value) {
    cout << "Integer: " << value << endl;
}

void print(double value) {
    cout << "Double: " << value << endl;
}

void print(const string& value) {
    cout << "String: " << value << endl;
}

// Default parameters
void greet(string name, string greeting = "Hello") {
    cout << greeting << ", " << name << "!" << endl;
}

// References (safer alternative to pointers)
void swap(int& a, int& b) {
    int temp = a;
    a = b;
    b = temp;
}

int main() {
    // C++ specific types
    bool isCppFun = true;
    cout << "Is C++ fun? " << boolalpha << isCppFun << endl;
    
    // Function overloading demonstration
    print(42);
    print(3.14159);
    print("Hello C++");
    
    // Default parameters
    greet("Alice");
    greet("Bob", "Good morning");
    
    // References
    int x = 10, y = 20;
    cout << "Before swap: x=" << x << ", y=" << y << endl;
    swap(x, y);
    cout << "After swap: x=" << x << ", y=" << y << endl;
    
    // Reference variables
    int original = 100;
    int& ref = original;  // ref is an alias for original
    ref = 200;
    cout << "original: " << original << ", ref: " << ref << endl;
    
    return 0;
}

Namespaces and Scope Resolution

Namespaces help organize code and prevent naming conflicts. The scope resolution operator (::) allows access to global and namespace members.
#include <iostream>
#include <string>

// Custom namespace
namespace MathOperations {
    const double PI = 3.14159;
    
    double add(double a, double b) {
        return a + b;
    }
    
    double multiply(double a, double b) {
        return a * b;
    }
    
    // Nested namespace
    namespace Geometry {
        double circleArea(double radius) {
            return PI * radius * radius;
        }
    }
}

// Global variable
int globalVar = 100;

// Another namespace
namespace StringUtils {
    void printLength(const std::string& str) {
        std::cout << "Length: " << str.length() << std::endl;
    }
}

int main() {
    // Using namespace members
    std::cout << "PI: " << MathOperations::PI << std::endl;
    std::cout << "5 + 3 = " << MathOperations::add(5, 3) << std::endl;
    std::cout << "Circle area: " << MathOperations::Geometry::circleArea(5.0) << std::endl;
    
    // Using directive
    using StringUtils::printLength;
    printLength("Hello C++");
    
    // Scope resolution for global variables
    int globalVar = 50;  // Local variable shadows global
    std::cout << "Local globalVar: " << globalVar << std::endl;
    std::cout << "Global globalVar: " << ::globalVar << std::endl;
    
    // Creating alias for long namespace
    namespace MO = MathOperations;
    std::cout << "Using alias: " << MO::multiply(4, 5) << std::endl;
    
    return 0;
}

Memory Management: new and delete

C++ provides operators new and delete for dynamic memory management, offering better type safety and initialization compared to malloc/free.
#include <iostream>
using namespace std;

class Point {
public:
    int x, y;
    Point(int x = 0, int y = 0) : x(x), y(y) {
        cout << "Point constructed: (" << x << ", " << y << ")" << endl;
    }
    ~Point() {
        cout << "Point destroyed: (" << x << ", " << y << ")" << endl;
    }
};

int main() {
    // Single object allocation
    Point* p1 = new Point(10, 20);
    cout << "p1: (" << p1->x << ", " << p1->y << ")" << endl;
    
    // Array allocation
    int size = 5;
    int* arr = new int[size];
    for (int i = 0; i < size; i++) {
        arr[i] = (i + 1) * 10;
    }
    
    cout << "Array elements: ";
    for (int i = 0; i < size; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;
    
    // Array of objects
    Point* points = new Point[3] {
        Point(1, 1),
        Point(2, 2),
        Point(3, 3)
    };
    
    // Memory deallocation
    delete p1;           // Single object
    delete[] arr;        // Array of primitives
    delete[] points;     // Array of objects
    
    // Memory allocation with initialization
    int* value = new int(42);  // Initialize with 42
    cout << "Initialized value: " << *value << endl;
    delete value;
    
    // Checking for allocation failure (modern approach uses exceptions)
    try {
        int* hugeArray = new int[1000000000000LL]; // Very large allocation
        delete[] hugeArray;
    } catch (const bad_alloc& e) {
        cout << "Memory allocation failed: " << e.what() << endl;
    }
    
    return 0;
}

2. Classes & Object-Oriented Programming

Class Basics: Encapsulation and Abstraction

Classes are the foundation of C++ OOP. They encapsulate data and behavior, providing abstraction and data hiding through access specifiers.
#include <iostream>
#include <string>
using namespace std;

class BankAccount {
private:
    string accountNumber;
    string accountHolder;
    double balance;
    
    // Private helper method
    bool isValidAmount(double amount) const {
        return amount > 0;
    }

public:
    // Constructor
    BankAccount(const string& number, const string& holder, double initialBalance = 0.0)
        : accountNumber(number), accountHolder(holder), balance(initialBalance) {
        cout << "Account created for " << holder << endl;
    }
    
    // Destructor
    ~BankAccount() {
        cout << "Account " << accountNumber << " is being closed" << endl;
    }
    
    // Public interface
    void deposit(double amount) {
        if (isValidAmount(amount)) {
            balance += amount;
            cout << "Deposited: $" << amount << endl;
        } else {
            cout << "Invalid deposit amount!" << endl;
        }
    }
    
    bool withdraw(double amount) {
        if (isValidAmount(amount) && amount <= balance) {
            balance -= amount;
            cout << "Withdrawn: $" << amount << endl;
            return true;
        }
        cout << "Withdrawal failed!" << endl;
        return false;
    }
    
    // Const member function - doesn't modify object state
    double getBalance() const {
        return balance;
    }
    
    void displayInfo() const {
        cout << "Account: " << accountNumber << endl;
        cout << "Holder: " << accountHolder << endl;
        cout << "Balance: $" << balance << endl;
    }
    
    // Static member
    static string getBankName() {
        return "C++ Bank";
    }
};

int main() {
    // Creating objects
    BankAccount account1("123456", "Alice", 1000.0);
    BankAccount account2("789012", "Bob");
    
    // Using object methods
    account1.displayInfo();
    account1.deposit(500.0);
    account1.withdraw(200.0);
    account1.withdraw(2000.0); // Should fail
    
    cout << "Current balance: $" << account1.getBalance() << endl;
    
    // Static member access
    cout << "Bank name: " << BankAccount::getBankName() << endl;
    
    return 0;
    // Destructors called automatically when objects go out of scope
}

Inheritance and Polymorphism

Inheritance allows creating new classes based on existing ones. Polymorphism enables treating objects of different classes uniformly through base class pointers/references.
#include <iostream>
#include <string>
#include <vector>
using namespace std;

// Base class
class Shape {
protected:
    string name;
    string color;

public:
    Shape(const string& n, const string& c) : name(n), color(c) {}
    
    // Virtual function for polymorphism
    virtual double area() const = 0; // Pure virtual function
    
    virtual void display() const {
        cout << "Shape: " << name << ", Color: " << color;
    }
    
    // Virtual destructor for proper cleanup
    virtual ~Shape() {
        cout << "Shape " << name << " destroyed" << endl;
    }
};

// Derived class
class Circle : public Shape {
private:
    double radius;

public:
    Circle(const string& n, const string& c, double r) 
        : Shape(n, c), radius(r) {}
    
    // Override base class function
    double area() const override {
        return 3.14159 * radius * radius;
    }
    
    void display() const override {
        Shape::display();
        cout << ", Radius: " << radius << ", Area: " << area() << endl;
    }
};

class Rectangle : public Shape {
private:
    double width, height;

public:
    Rectangle(const string& n, const string& c, double w, double h)
        : Shape(n, c), width(w), height(h) {}
    
    double area() const override {
        return width * height;
    }
    
    void display() const override {
        Shape::display();
        cout << ", Width: " << width << ", Height: " << height 
             << ", Area: " << area() << endl;
    }
};

int main() {
    // Polymorphism in action
    vector<Shape*> shapes;
    
    shapes.push_back(new Circle("Circle1", "Red", 5.0));
    shapes.push_back(new Rectangle("Rect1", "Blue", 4.0, 6.0));
    shapes.push_back(new Circle("Circle2", "Green", 3.0));
    
    cout << "Polymorphic behavior:" << endl;
    for (Shape* shape : shapes) {
        shape->display();  // Calls appropriate derived class function
    }
    
    // Cleanup
    for (Shape* shape : shapes) {
        delete shape;
    }
    
    // Object slicing demonstration
    Circle circle("MyCircle", "Yellow", 10.0);
    Shape shape = circle;  // Object slicing - Circle part is lost
    shape.display();
    cout << endl;
    
    return 0;
}

Operator Overloading

C++ allows redefining most operators for user-defined types, enabling natural syntax for custom classes.
#include <iostream>
#include <cmath>
using namespace std;

class Vector3D {
private:
    double x, y, z;

public:
    // Constructors
    Vector3D(double x = 0, double y = 0, double z = 0) : x(x), y(y), z(z) {}
    
    // Operator overloading
    Vector3D operator+(const Vector3D& other) const {
        return Vector3D(x + other.x, y + other.y, z + other.z);
    }
    
    Vector3D operator-(const Vector3D& other) const {
        return Vector3D(x - other.x, y - other.y, z - other.z);
    }
    
    // Dot product
    double operator*(const Vector3D& other) const {
        return x * other.x + y * other.y + z * other.z;
    }
    
    // Scalar multiplication
    Vector3D operator*(double scalar) const {
        return Vector3D(x * scalar, y * scalar, z * scalar);
    }
    
    // Friend function for commutative scalar multiplication
    friend Vector3D operator*(double scalar, const Vector3D& vec);
    
    // Compound assignment
    Vector3D& operator+=(const Vector3D& other) {
        x += other.x;
        y += other.y;
        z += other.z;
        return *this;
    }
    
    // Comparison operators
    bool operator==(const Vector3D& other) const {
        return x == other.x && y == other.y && z == other.z;
    }
    
    bool operator!=(const Vector3D& other) const {
        return !(*this == other);
    }
    
    // Subscript operator
    double operator[](int index) const {
        switch(index) {
            case 0: return x;
            case 1: return y;
            case 2: return z;
            default: throw out_of_range("Index out of range");
        }
    }
    
    // Output stream operator
    friend ostream& operator<<(ostream& os, const Vector3D& vec);
    
    // Magnitude
    double magnitude() const {
        return sqrt(x*x + y*y + z*z);
    }
    
    // Normalize
    Vector3D normalize() const {
        double mag = magnitude();
        if (mag == 0) return *this;
        return *this * (1.0 / mag);
    }
};

// Friend function definitions
Vector3D operator*(double scalar, const Vector3D& vec) {
    return vec * scalar;  // Reuse member function
}

ostream& operator<<(ostream& os, const Vector3D& vec) {
    os << "(" << vec.x << ", " << vec.y << ", " << vec.z << ")";
    return os;
}

int main() {
    Vector3D v1(1, 2, 3);
    Vector3D v2(4, 5, 6);
    
    cout << "v1 = " << v1 << endl;
    cout << "v2 = " << v2 << endl;
    
    Vector3D v3 = v1 + v2;
    cout << "v1 + v2 = " << v3 << endl;
    
    Vector3D v4 = v1 - v2;
    cout << "v1 - v2 = " << v4 << endl;
    
    double dot = v1 * v2;
    cout << "v1 · v2 = " << dot << endl;
    
    Vector3D v5 = v1 * 2.5;
    cout << "v1 * 2.5 = " << v5 << endl;
    
    Vector3D v6 = 3.0 * v1;
    cout << "3.0 * v1 = " << v6 << endl;
    
    v1 += v2;
    cout << "v1 after += v2: " << v1 << endl;
    
    cout << "v1 magnitude: " << v1.magnitude() << endl;
    cout << "v1 normalized: " << v1.normalize() << endl;
    
    cout << "v1[0] = " << v1[0] << ", v1[1] = " << v1[1] << ", v1[2] = " << v1[2] << endl;
    
    return 0;
}

Friend Functions and Static Members

Friend functions can access private members of classes. Static members are shared across all instances of a class.
#include <iostream>
#include <vector>
using namespace std;

class Student {
private:
    string name;
    int id;
    double gpa;
    
    // Static member - shared by all Student objects
    static int totalStudents;
    static int nextId;

public:
    Student(const string& n, double g) : name(n), gpa(g), id(nextId++) {
        totalStudents++;
    }
    
    ~Student() {
        totalStudents--;
    }
    
    // Friend function declaration
    friend void displayStudentInfo(const Student& s);
    
    // Friend class
    friend class StudentManager;
    
    // Static member functions
    static int getTotalStudents() {
        return totalStudents;
    }
    
    static void resetIds() {
        nextId = 1000; // Start IDs from 1000
    }
    
    // Regular member functions
    string getName() const { return name; }
    double getGpa() const { return gpa; }
    int getId() const { return id; }
};

// Static member definitions
int Student::totalStudents = 0;
int Student::nextId = 1000;

// Friend function definition
void displayStudentInfo(const Student& s) {
    cout << "Student ID: " << s.id << endl;  // Can access private members
    cout << "Name: " << s.name << endl;
    cout << "GPA: " << s.gpa << endl;
}

// Friend class
class StudentManager {
private:
    vector<Student*> students;

public:
    void addStudent(Student* student) {
        students.push_back(student);
    }
    
    void displayAllStudents() {
        cout << "=== All Students ===" << endl;
        for (Student* s : students) {
            // Can access private members because friend
            cout << s->id << ": " << s->name << " (GPA: " << s->gpa << ")" << endl;
        }
    }
    
    double getAverageGPA() const {
        if (students.empty()) return 0.0;
        
        double total = 0.0;
        for (Student* s : students) {
            total += s->gpa;  // Access private member
        }
        return total / students.size();
    }
};

int main() {
    // Demonstrate static members
    cout << "Initial total students: " << Student::getTotalStudents() << endl;
    
    Student s1("Alice", 3.8);
    Student s2("Bob", 3.2);
    Student s3("Charlie", 3.9);
    
    cout << "After creating 3 students: " << Student::getTotalStudents() << endl;
    
    // Using friend function
    cout << "\nUsing friend function:" << endl;
    displayStudentInfo(s1);
    
    // Using friend class
    StudentManager manager;
    manager.addStudent(&s1);
    manager.addStudent(&s2);
    manager.addStudent(&s3);
    
    manager.displayAllStudents();
    cout << "Average GPA: " << manager.getAverageGPA() << endl;
    
    // Demonstrate object destruction
    {
        Student temp("Temporary", 2.5);
        cout << "Total students in block: " << Student::getTotalStudents() << endl;
    } // temp destroyed here
    
    cout << "After block: " << Student::getTotalStudents() << endl;
    
    return 0;
}

3. Templates & Generic Programming

Function Templates

Function templates allow writing generic functions that work with any data type. The compiler generates specific versions as needed.
#include <iostream>
#include <string>
#include <vector>
using namespace std;

// Basic function template
template<typename T>
T max(const T& a, const T& b) {
    return (a > b) ? a : b;
}

// Template with multiple types
template<typename T1, typename T2>
void printPair(const T1& first, const T2& second) {
    cout << "(" << first << ", " << second << ")" << endl;
}

// Template specialization
template<>
const char* max(const char* const & a, const char* const & b) {
    return (strcmp(a, b) > 0) ? a : b;
}

// Template with non-type parameters
template<typename T, int size>
class FixedArray {
private:
    T data[size];

public:
    T& operator[](int index) {
        if (index < 0 || index >= size) {
            throw out_of_range("Index out of bounds");
        }
        return data[index];
    }
    
    const T& operator[](int index) const {
        if (index < 0 || index >= size) {
            throw out_of_range("Index out of bounds");
        }
        return data[index];
    }
    
    int getSize() const { return size; }
};

// Variadic templates (C++11)
template<typename T>
void print(const T& value) {
    cout << value << endl;
}

template<typename T, typename... Args>
void print(const T& first, const Args&... rest) {
    cout << first << " ";
    print(rest...);
}

int main() {
    // Using function templates
    cout << "max(5, 10) = " << max(5, 10) << endl;
    cout << "max(3.14, 2.71) = " << max(3.14, 2.71) << endl;
    cout << "max('a', 'z') = " << max('a', 'z') << endl;
    
    string s1 = "hello", s2 = "world";
    cout << "max(strings) = " << max(s1, s2) << endl;
    
    // Using specialized version for C-strings
    cout << "max(C-strings) = " << max("apple", "banana") << endl;
    
    // Multiple type parameters
    printPair(42, "answer");
    printPair(3.14, "pi");
    
    // Non-type template parameters
    FixedArray<int, 5> intArray;
    for (int i = 0; i < intArray.getSize(); i++) {
        intArray[i] = (i + 1) * 10;
    }
    
    cout << "Fixed array: ";
    for (int i = 0; i < intArray.getSize(); i++) {
        cout << intArray[i] << " ";
    }
    cout << endl;
    
    // Variadic templates
    print(1, 2, 3, "hello", 4.5, 'X');
    
    return 0;
}

Class Templates

Class templates enable creating generic classes that can work with any data type. They are fundamental to the C++ Standard Template Library (STL).
#include <iostream>
#include <vector>
#include <stdexcept>
using namespace std;

// Basic class template
template<typename T>
class Stack {
private:
    vector<T> elements;

public:
    // Push element onto stack
    void push(const T& value) {
        elements.push_back(value);
    }
    
    // Pop element from stack
    void pop() {
        if (elements.empty()) {
            throw out_of_range("Stack<>::pop(): empty stack");
        }
        elements.pop_back();
    }
    
    // Get top element
    T top() const {
        if (elements.empty()) {
            throw out_of_range("Stack<>::top(): empty stack");
        }
        return elements.back();
    }
    
    // Check if stack is empty
    bool empty() const {
        return elements.empty();
    }
    
    // Get size
    size_t size() const {
        return elements.size();
    }
};

// Template with default parameters
template<typename T = int, int initialCapacity = 10>
class DynamicArray {
private:
    T* data;
    int capacity;
    int count;

public:
    DynamicArray() : capacity(initialCapacity), count(0) {
        data = new T[capacity];
    }
    
    ~DynamicArray() {
        delete[] data;
    }
    
    void add(const T& value) {
        if (count >= capacity) {
            // Resize
            capacity *= 2;
            T* newData = new T[capacity];
            for (int i = 0; i < count; i++) {
                newData[i] = data[i];
            }
            delete[] data;
            data = newData;
        }
        data[count++] = value;
    }
    
    T& operator[](int index) {
        if (index < 0 || index >= count) {
            throw out_of_range("Index out of bounds");
        }
        return data[index];
    }
    
    int size() const { return count; }
    int getCapacity() const { return capacity; }
};

// Template inheritance
template<typename T>
class LoggingStack : public Stack<T> {
public:
    void push(const T& value) {
        cout << "Pushing: " << value << endl;
        Stack<T>::push(value);
    }
    
    void pop() {
        if (!this->empty()) {
            cout << "Popping: " << this->top() << endl;
            Stack<T>::pop();
        }
    }
};

int main() {
    // Using class template
    Stack<int> intStack;
    
    intStack.push(10);
    intStack.push(20);
    intStack.push(30);
    
    cout << "Stack size: " << intStack.size() << endl;
    cout << "Top element: " << intStack.top() << endl;
    
    intStack.pop();
    cout << "After pop, top: " << intStack.top() << endl;
    
    // Stack with strings
    Stack<string> stringStack;
    stringStack.push("hello");
    stringStack.push("world");
    cout << "String stack top: " << stringStack.top() << endl;
    
    // Using template with default parameters
    DynamicArray<> defaultArray;  // Uses default types (int, capacity 10)
    DynamicArray<double, 5> doubleArray;
    
    for (int i = 0; i < 15; i++) {
        defaultArray.add(i * 10);
    }
    
    cout << "Default array size: " << defaultArray.size() 
         << ", capacity: " << defaultArray.getCapacity() << endl;
    
    // Using derived template class
    LoggingStack<int> loggingStack;
    loggingStack.push(100);
    loggingStack.push(200);
    loggingStack.pop();
    
    return 0;
}

4. STL Containers & Algorithms

STL Containers: Vector, List, Map

The Standard Template Library provides powerful container classes that handle memory management and provide efficient operations.
#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <unordered_map>
#include <set>
#include <algorithm>
#include <string>
using namespace std;

void demonstrateVector() {
    cout << "=== VECTOR ===" << endl;
    vector<int> vec = {1, 2, 3, 4, 5};
    
    // Adding elements
    vec.push_back(6);
    vec.insert(vec.begin() + 2, 99);
    
    // Accessing elements
    cout << "Element at index 2: " << vec[2] << endl;
    cout << "Front: " << vec.front() << ", Back: " << vec.back() << endl;
    
    // Iterating
    cout << "Elements: ";
    for (auto it = vec.begin(); it != vec.end(); ++it) {
        cout << *it << " ";
    }
    cout << endl;
    
    // Range-based for loop (C++11)
    cout << "Range-based: ";
    for (int value : vec) {
        cout << value << " ";
    }
    cout << endl;
    
    // Capacity
    cout << "Size: " << vec.size() << ", Capacity: " << vec.capacity() << endl;
}

void demonstrateList() {
    cout << "\n=== LIST ===" << endl;
    list<string> names = {"Alice", "Bob", "Charlie"};
    
    names.push_front("First");
    names.push_back("Last");
    
    // List-specific operations
    names.sort();
    names.unique();
    
    cout << "Names: ";
    for (const auto& name : names) {
        cout << name << " ";
    }
    cout << endl;
}

void demonstrateMap() {
    cout << "\n=== MAP ===" << endl;
    map<string, int> ageMap = {
        {"Alice", 25},
        {"Bob", 30},
        {"Charlie", 35}
    };
    
    // Inserting
    ageMap["Diana"] = 28;
    ageMap.insert({"Eve", 32});
    
    // Accessing
    cout << "Alice's age: " << ageMap["Alice"] << endl;
    
    // Iterating through map
    cout << "All ages:" << endl;
    for (const auto& pair : ageMap) {
        cout << pair.first << ": " << pair.second << endl;
    }
    
    // Finding elements
    auto it = ageMap.find("Bob");
    if (it != ageMap.end()) {
        cout << "Found Bob: " << it->second << endl;
    }
}

void demonstrateAlgorithms() {
    cout << "\n=== ALGORITHMS ===" << endl;
    vector<int> numbers = {5, 2, 8, 1, 9, 3, 7, 4, 6};
    
    // Sorting
    sort(numbers.begin(), numbers.end());
    cout << "Sorted: ";
    for (int n : numbers) cout << n << " ";
    cout << endl;
    
    // Finding
    auto found = find(numbers.begin(), numbers.end(), 7);
    if (found != numbers.end()) {
        cout << "Found 7 at position: " << distance(numbers.begin(), found) << endl;
    }
    
    // Counting
    int countFives = count(numbers.begin(), numbers.end(), 5);
    cout << "Number of 5s: " << countFives << endl;
    
    // Lambda expressions with algorithms (C++11)
    cout << "Even numbers: ";
    for_each(numbers.begin(), numbers.end(), [](int n) {
        if (n % 2 == 0) cout << n << " ";
    });
    cout << endl;
    
    // Transform
    vector<int> squared;
    transform(numbers.begin(), numbers.end(), back_inserter(squared),
              [](int n) { return n * n; });
    
    cout << "Squared: ";
    for (int n : squared) cout << n << " ";
    cout << endl;
}

int main() {
    demonstrateVector();
    demonstrateList();
    demonstrateMap();
    demonstrateAlgorithms();
    
    return 0;
}

Smart Pointers (C++11 and beyond)

Smart pointers automate memory management, preventing memory leaks and making code safer and more maintainable.
#include <iostream>
#include <memory>
#include <vector>
using namespace std;

class Resource {
private:
    string name;
    
public:
    Resource(const string& n) : name(n) {
        cout << "Resource " << name << " created" << endl;
    }
    
    ~Resource() {
        cout << "Resource " << name << " destroyed" << endl;
    }
    
    void use() {
        cout << "Using resource " << name << endl;
    }
    
    string getName() const { return name; }
};

void demonstrateUniquePtr() {
    cout << "=== UNIQUE_PTR ===" << endl;
    
    // Creating unique_ptr
    unique_ptr<Resource> res1 = make_unique<Resource>("Unique1");
    res1->use();
    
    // Transfer ownership (move semantics)
    unique_ptr<Resource> res2 = move(res1);
    if (!res1) {
        cout << "res1 is now empty" << endl;
    }
    res2->use();
    
    // unique_ptr in containers
    vector<unique_ptr<Resource>> resources;
    resources.push_back(make_unique<Resource>("Vector1"));
    resources.push_back(make_unique<Resource>("Vector2"));
    
    for (const auto& res : resources) {
        res->use();
    }
} // Resources automatically destroyed here

void demonstrateSharedPtr() {
    cout << "\n=== SHARED_PTR ===" << endl;
    
    // Creating shared_ptr
    shared_ptr<Resource> res1 = make_shared<Resource>("Shared1");
    cout << "Use count: " << res1.use_count() << endl;
    
    {
        shared_ptr<Resource> res2 = res1;  // Share ownership
        cout << "Use count after sharing: " << res1.use_count() << endl;
        res2->use();
    } // res2 destroyed, but resource remains
    
    cout << "Use count after res2 destruction: " << res1.use_count() << endl;
    res1->use();
}

void demonstrateWeakPtr() {
    cout << "\n=== WEAK_PTR ===" << endl;
    
    shared_ptr<Resource> shared = make_shared<Resource>("WeakDemo");
    weak_ptr<Resource> weak = shared;
    
    cout << "Shared use count: " << shared.use_count() << endl;
    
    // Using weak_ptr
    if (auto temp = weak.lock()) {
        cout << "Resource is alive: " << temp->getName() << endl;
    } else {
        cout << "Resource has been destroyed" << endl;
    }
    
    // Reset shared pointer
    shared.reset();
    cout << "After reset, shared use count: " << shared.use_count() << endl;
    
    if (auto temp = weak.lock()) {
        cout << "Resource is still alive" << endl;
    } else {
        cout << "Resource has been destroyed" << endl;
    }
}

// Custom deleter for unique_ptr
void customDeleter(Resource* res) {
    cout << "Custom deleter called for " << res->getName() << endl;
    delete res;
}

int main() {
    demonstrateUniquePtr();
    demonstrateSharedPtr();
    demonstrateWeakPtr();
    
    // Using custom deleter
    cout << "\n=== CUSTOM DELETER ===" << endl;
    unique_ptr<Resource, decltype(&customDeleter)> customRes(
        new Resource("Custom"), customDeleter);
    customRes->use();
    
    return 0;
}

💻 C++ Practice Projects

Beginner Level

  • 1Create a Bank Account Management System with classes
  • 2Build a Simple Calculator with operator overloading
  • 3Implement a Student Grade Management System
  • 4Create a Vector Mathematics Library with operator overloading
  • 5Build a Contact Management System with file I/O

Intermediate Level

  • 1Develop a Template-based Stack and Queue library
  • 2Create a Smart Pointer implementation from scratch
  • 3Build a Matrix Class with arithmetic operations
  • 4Implement a Custom String Class with dynamic memory
  • 5Create a Generic Sorting Algorithm library

Advanced Level

  • 1Build a Multithreaded Task Scheduler
  • 2Create a Memory Pool Allocator with custom new/delete
  • 3Implement a Simple Game Engine with polymorphism
  • 4Develop a Template Metaprogramming library
  • 5Build a Network Server with RAII and smart pointers

📋 C++ Quick Reference

Modern C++ Features

  • auto - Type deduction
  • lambda - Anonymous functions
  • range-based for - Simplified loops
  • smart pointers - Automatic memory management
  • move semantics - Efficient resource transfer
  • constexpr - Compile-time evaluation
  • nullptr - Type-safe null pointer

STL Containers

  • vector - Dynamic array
  • list - Doubly-linked list
  • map - Sorted key-value pairs
  • unordered_map - Hash table
  • set - Unique sorted elements
  • queue - FIFO container
  • stack - LIFO container

Master High-Performance Programming!

C++ remains the language of choice for performance-critical applications, game development, system software, and high-frequency trading. Its unique combination of high-level abstractions and low-level control provides unparalleled power and efficiency.

Modern C++ features make the language safer and more expressive while maintaining the performance that made C++ famous. Mastering C++ opens doors to cutting-edge software development careers.

Happy C++ Coding! ⚡

This comprehensive guide covers C++ from basic OOP concepts to modern features like smart pointers, templates, and STL.

Essential for game development, system programming, and high-performance applications.

© 2025 C++ Programming Mastery Guide | Power and Performance