cpp

examples

examples.cpp⚙️
/**
 * References in C++ - Comprehensive Examples
 * 
 * Demonstrates:
 * - Reference declaration and initialization
 * - References vs pointers
 * - Pass by reference
 * - const references
 * - Reference use cases
 * 
 * Compile: g++ -std=c++17 -Wall -Wextra examples.cpp -o examples
 * Run: ./examples
 */

#include <iostream>
#include <string>
#include <vector>

using namespace std;

// ============================================================
// SECTION 1: REFERENCE BASICS
// ============================================================

void demonstrateBasicReference() {
    cout << "--- Basic Reference Concepts ---\n" << endl;
    
    int x = 10;
    int& ref = x;  // ref is an alias for x
    
    cout << "int x = 10;" << endl;
    cout << "int& ref = x;" << endl;
    cout << endl;
    
    cout << "x = " << x << endl;
    cout << "ref = " << ref << " (same value)" << endl;
    cout << "&x = " << &x << endl;
    cout << "&ref = " << &ref << " (same address!)" << endl;
    
    // Modifying through reference
    ref = 20;
    cout << "\nAfter ref = 20:" << endl;
    cout << "x = " << x << " (changed!)" << endl;
    cout << "ref = " << ref << endl;
    
    // Modifying original
    x = 30;
    cout << "\nAfter x = 30:" << endl;
    cout << "x = " << x << endl;
    cout << "ref = " << ref << " (also changed!)" << endl;
}

void demonstrateMultipleReferences() {
    cout << "\n--- Multiple References to Same Variable ---\n" << endl;
    
    int original = 100;
    int& ref1 = original;
    int& ref2 = original;
    int& ref3 = ref1;      // ref3 also refers to original, not ref1
    
    cout << "int original = 100;" << endl;
    cout << "int& ref1 = original;" << endl;
    cout << "int& ref2 = original;" << endl;
    cout << "int& ref3 = ref1;" << endl;
    cout << endl;
    
    cout << "original = " << original << endl;
    cout << "ref1 = " << ref1 << endl;
    cout << "ref2 = " << ref2 << endl;
    cout << "ref3 = " << ref3 << endl;
    
    cout << "\nAll have same address:" << endl;
    cout << "&original = " << &original << endl;
    cout << "&ref1 = " << &ref1 << endl;
    cout << "&ref2 = " << &ref2 << endl;
    cout << "&ref3 = " << &ref3 << endl;
    
    // Modify through any of them
    ref2 = 200;
    cout << "\nAfter ref2 = 200, all show: " << original << endl;
}

void demonstrateDifferentTypes() {
    cout << "\n--- References to Different Types ---\n" << endl;
    
    // Integer reference
    int num = 42;
    int& numRef = num;
    cout << "int reference: numRef = " << numRef << endl;
    
    // Double reference
    double pi = 3.14159;
    double& piRef = pi;
    cout << "double reference: piRef = " << piRef << endl;
    
    // String reference
    string name = "Alice";
    string& nameRef = name;
    cout << "string reference: nameRef = " << nameRef << endl;
    
    // Modify through references
    nameRef = "Bob";
    cout << "After nameRef = \"Bob\": name = " << name << endl;
    
    // Vector reference
    vector<int> nums = {1, 2, 3, 4, 5};
    vector<int>& numsRef = nums;
    numsRef.push_back(6);
    cout << "Vector after push_back through reference: ";
    for (int n : nums) cout << n << " ";
    cout << endl;
}

// ============================================================
// SECTION 2: REFERENCES VS POINTERS
// ============================================================

void demonstrateReferenceVsPointer() {
    cout << "\n--- Reference vs Pointer Comparison ---\n" << endl;
    
    int x = 10;
    int y = 20;
    
    // Pointer
    int* ptr = &x;
    cout << "Pointer:" << endl;
    cout << "  *ptr = " << *ptr << " (must dereference)" << endl;
    ptr = &y;  // Can reassign
    cout << "  After ptr = &y, *ptr = " << *ptr << endl;
    
    // Reference
    int& ref = x;
    cout << "\nReference:" << endl;
    cout << "  ref = " << ref << " (direct access)" << endl;
    ref = y;  // This assigns y's VALUE to x, doesn't rebind!
    cout << "  After ref = y:" << endl;
    cout << "    ref = " << ref << endl;
    cout << "    x = " << x << " (x now has y's value!)" << endl;
    cout << "    y = " << y << " (unchanged)" << endl;
}

void demonstrateSyntaxDifference() {
    cout << "\n--- Syntax Differences ---\n" << endl;
    
    struct Person {
        string name;
        int age;
    };
    
    Person person = {"Alice", 30};
    
    // With pointer
    Person* personPtr = &person;
    cout << "Pointer syntax: personPtr->name = " << personPtr->name << endl;
    cout << "                (*personPtr).age = " << (*personPtr).age << endl;
    
    // With reference
    Person& personRef = person;
    cout << "\nReference syntax: personRef.name = " << personRef.name << endl;
    cout << "                  personRef.age = " << personRef.age << endl;
}

// ============================================================
// SECTION 3: PASS BY REFERENCE
// ============================================================

// Pass by value - copies the argument
void incrementByValue(int x) {
    x++;  // Only modifies the copy
}

// Pass by reference - uses the original
void incrementByReference(int& x) {
    x++;  // Modifies the original
}

// Pass by pointer - uses the original (pointer syntax)
void incrementByPointer(int* x) {
    (*x)++;  // Modifies the original
}

void demonstratePassingMethods() {
    cout << "\n--- Pass by Value vs Reference vs Pointer ---\n" << endl;
    
    int a = 10, b = 10, c = 10;
    
    cout << "Initial values: a = " << a << ", b = " << b << ", c = " << c << endl;
    
    incrementByValue(a);
    incrementByReference(b);
    incrementByPointer(&c);
    
    cout << "After increment functions:" << endl;
    cout << "  a (by value): " << a << " (unchanged)" << endl;
    cout << "  b (by reference): " << b << " (incremented)" << endl;
    cout << "  c (by pointer): " << c << " (incremented)" << endl;
}

// Swap functions
void swapByValue(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
    // Only local copies are swapped!
}

void swapByReference(int& a, int& b) {
    int temp = a;
    a = b;
    b = temp;
    // Originals are swapped!
}

void demonstrateSwap() {
    cout << "\n--- Swap Function Comparison ---\n" << endl;
    
    int x = 10, y = 20;
    cout << "Before swap: x = " << x << ", y = " << y << endl;
    
    swapByValue(x, y);
    cout << "After swapByValue: x = " << x << ", y = " << y << " (unchanged!)" << endl;
    
    swapByReference(x, y);
    cout << "After swapByReference: x = " << x << ", y = " << y << " (swapped!)" << endl;
}

// Avoiding copies with large objects
void processVectorByCopy(vector<int> vec) {
    cout << "  Received vector by copy (size: " << vec.size() << ")" << endl;
}

void processVectorByReference(vector<int>& vec) {
    cout << "  Received vector by reference (size: " << vec.size() << ")" << endl;
    vec.push_back(100);  // Can modify!
}

void processVectorByConstReference(const vector<int>& vec) {
    cout << "  Received vector by const reference (size: " << vec.size() << ")" << endl;
    // vec.push_back(100);  // ERROR: can't modify through const reference
}

void demonstrateLargeObjectPassing() {
    cout << "\n--- Passing Large Objects ---\n" << endl;
    
    vector<int> bigVector(1000000, 42);  // 1 million elements
    
    cout << "Vector size: " << bigVector.size() << endl;
    
    cout << "\nPassing by copy (SLOW - copies all elements):" << endl;
    processVectorByCopy(bigVector);
    
    cout << "\nPassing by reference (FAST - no copy):" << endl;
    processVectorByReference(bigVector);
    cout << "  Vector now has size: " << bigVector.size() << " (modified)" << endl;
    
    cout << "\nPassing by const reference (FAST + safe):" << endl;
    processVectorByConstReference(bigVector);
}

// ============================================================
// SECTION 4: CONST REFERENCES
// ============================================================

void demonstrateConstReference() {
    cout << "\n--- const References ---\n" << endl;
    
    int x = 10;
    
    int& ref = x;           // Non-const reference
    const int& constRef = x; // Const reference
    
    cout << "int x = 10;" << endl;
    cout << "int& ref = x;" << endl;
    cout << "const int& constRef = x;" << endl;
    
    ref = 20;  // OK: can modify through non-const reference
    cout << "\nAfter ref = 20: x = " << x << endl;
    
    // constRef = 30;  // ERROR: cannot modify through const reference
    cout << "constRef = 30 would cause ERROR" << endl;
    
    cout << "\nconstRef still shows current value: " << constRef << endl;
}

void demonstrateConstRefToTemporary() {
    cout << "\n--- const Reference to Temporaries ---\n" << endl;
    
    // const references can bind to literals and temporaries
    const int& intRef = 42;
    const double& dblRef = 3.14;
    const string& strRef = "Hello, World!";
    
    cout << "const int& intRef = 42 → " << intRef << endl;
    cout << "const double& dblRef = 3.14 → " << dblRef << endl;
    cout << "const string& strRef = \"Hello, World!\" → " << strRef << endl;
    
    // Non-const references cannot bind to temporaries
    // int& badRef = 42;  // ERROR!
    cout << "\nint& badRef = 42 would cause ERROR" << endl;
    
    // Useful for function parameters
    cout << "\nThis allows functions to accept both variables and literals:" << endl;
    cout << "void print(const string& s);  // Can call with \"literal\" or variable" << endl;
}

void printMessage(const string& msg) {
    cout << "  Message: " << msg << endl;
}

void demonstrateConstRefInFunctions() {
    cout << "\n--- const Reference Parameters ---\n" << endl;
    
    string greeting = "Hello!";
    
    cout << "Calling printMessage with variable:" << endl;
    printMessage(greeting);
    
    cout << "\nCalling printMessage with literal:" << endl;
    printMessage("Goodbye!");  // Works because parameter is const&
    
    cout << "\nCalling printMessage with expression:" << endl;
    printMessage(greeting + " How are you?");  // Temporary from concatenation
}

// ============================================================
// SECTION 5: RETURN BY REFERENCE
// ============================================================

class IntArray {
private:
    int data[10];
    
public:
    IntArray() {
        for (int i = 0; i < 10; i++) {
            data[i] = i * 10;
        }
    }
    
    // Return by reference for element access
    int& at(int index) {
        return data[index];
    }
    
    // Return by const reference for read-only access
    const int& at(int index) const {
        return data[index];
    }
    
    void print() const {
        cout << "Array: ";
        for (int i = 0; i < 10; i++) {
            cout << data[i] << " ";
        }
        cout << endl;
    }
};

void demonstrateReturnByReference() {
    cout << "\n--- Return by Reference ---\n" << endl;
    
    IntArray arr;
    arr.print();
    
    cout << "\nAccessing element: arr.at(3) = " << arr.at(3) << endl;
    
    cout << "Modifying through reference: arr.at(3) = 999" << endl;
    arr.at(3) = 999;  // This works because at() returns reference!
    
    arr.print();
    
    cout << "\nChained operations: arr.at(5) += 100" << endl;
    arr.at(5) += 100;
    arr.print();
}

// ============================================================
// SECTION 6: RANGE-BASED FOR WITH REFERENCES
// ============================================================

void demonstrateRangeBasedFor() {
    cout << "\n--- Range-based For with References ---\n" << endl;
    
    vector<int> nums = {1, 2, 3, 4, 5};
    
    cout << "Original vector: ";
    for (int n : nums) cout << n << " ";
    cout << endl;
    
    // Without reference - copies each element
    cout << "\nTrying to double without reference:" << endl;
    for (int n : nums) {
        n *= 2;  // Modifies copy only!
    }
    cout << "Result: ";
    for (int n : nums) cout << n << " ";
    cout << " (unchanged!)" << endl;
    
    // With reference - modifies original
    cout << "\nDoubling with reference:" << endl;
    for (int& n : nums) {
        n *= 2;  // Modifies original!
    }
    cout << "Result: ";
    for (int n : nums) cout << n << " ";
    cout << " (doubled!)" << endl;
    
    // const reference for read-only access
    cout << "\nUsing const reference (efficient read-only):" << endl;
    int sum = 0;
    for (const int& n : nums) {
        sum += n;
    }
    cout << "Sum: " << sum << endl;
}

void demonstrateAutoWithReferences() {
    cout << "\n--- auto with References ---\n" << endl;
    
    vector<string> names = {"Alice", "Bob", "Charlie"};
    
    cout << "Original names: ";
    for (const auto& name : names) cout << name << " ";
    cout << endl;
    
    // auto& for modification
    cout << "\nAdding '!' to each name using auto&:" << endl;
    for (auto& name : names) {
        name += "!";
    }
    
    cout << "Result: ";
    for (const auto& name : names) cout << name << " ";
    cout << endl;
}

// ============================================================
// SECTION 7: REFERENCE PITFALLS
// ============================================================

// DANGEROUS: Returns reference to local variable
// int& getDangling() {
//     int x = 10;
//     return x;  // DANGER: x is destroyed after return!
// }

// SAFE: Returns reference to member or parameter
class SafeContainer {
    int value;
public:
    SafeContainer(int v) : value(v) {}
    
    int& getValue() { return value; }  // OK: member outlives function
};

void demonstrateDanglingReferenceRisk() {
    cout << "\n--- Dangling Reference Warning ---\n" << endl;
    
    cout << "DANGEROUS pattern (DON'T DO THIS):" << endl;
    cout << "  int& getDangling() {" << endl;
    cout << "      int x = 10;" << endl;
    cout << "      return x;  // DANGER: x destroyed!" << endl;
    cout << "  }" << endl;
    
    cout << "\nSAFE patterns:" << endl;
    
    // Safe: return reference to member
    SafeContainer container(42);
    int& ref = container.getValue();
    cout << "  Return reference to member: " << ref << endl;
    
    // Safe: return by value
    cout << "  Return by value for local variables" << endl;
}

// ============================================================
// MAIN FUNCTION
// ============================================================

int main() {
    cout << "╔════════════════════════════════════════════════════════════════════╗" << endl;
    cout << "║                   C++ REFERENCES - EXAMPLES                        ║" << endl;
    cout << "║                     Aliases and Indirection                        ║" << endl;
    cout << "╚════════════════════════════════════════════════════════════════════╝" << endl;
    
    cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
    cout << "║              SECTION 1: Reference Basics                     ║" << endl;
    cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
    demonstrateBasicReference();
    demonstrateMultipleReferences();
    demonstrateDifferentTypes();
    
    cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
    cout << "║              SECTION 2: References vs Pointers               ║" << endl;
    cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
    demonstrateReferenceVsPointer();
    demonstrateSyntaxDifference();
    
    cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
    cout << "║              SECTION 3: Pass by Reference                    ║" << endl;
    cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
    demonstratePassingMethods();
    demonstrateSwap();
    demonstrateLargeObjectPassing();
    
    cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
    cout << "║              SECTION 4: const References                     ║" << endl;
    cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
    demonstrateConstReference();
    demonstrateConstRefToTemporary();
    demonstrateConstRefInFunctions();
    
    cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
    cout << "║              SECTION 5: Return by Reference                  ║" << endl;
    cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
    demonstrateReturnByReference();
    
    cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
    cout << "║              SECTION 6: Range-based For                      ║" << endl;
    cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
    demonstrateRangeBasedFor();
    demonstrateAutoWithReferences();
    
    cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
    cout << "║              SECTION 7: Reference Pitfalls                   ║" << endl;
    cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
    demonstrateDanglingReferenceRisk();
    
    cout << "\n╔════════════════════════════════════════════════════════════════════╗" << endl;
    cout << "║                       Examples Complete!                           ║" << endl;
    cout << "╚════════════════════════════════════════════════════════════════════╝" << endl;
    
    return 0;
}
Examples - C++ Tutorial | DeepML