CodeNebula
C++98corebeginner

References

C++98 · The Foundation · Compiler flag: -std=c++98

Explanation

Aliases for existing variables, providing another name to access the same data.

Real-World Scenario

Used in a game to refer to a player’s health without copying it.

Quick Snippet

snippet.cpp
int x = 10; int& ref = x;

Full Example

references.cpp
// CodeNebula - C++98 Example: References
// Compile: g++ -std=c++98 -Wall -Wextra -o example references.cpp

// Demonstrates references in C++98: declaration, aliasing behavior,
// pass-by-reference, const references, references vs pointers, and
// returning references from functions.

#include <iostream>
#include <string>

// ------------------------------------------------------------------
// Pass by value - makes a copy, original is unchanged
// ------------------------------------------------------------------
void incrementByValue(int x)
{
    ++x;
    std::cout << "    Inside incrementByValue: x = " << x << std::endl;
}

// ------------------------------------------------------------------
// Pass by reference - modifies the original
// ------------------------------------------------------------------
void incrementByRef(int& x)
{
    ++x;
    std::cout << "    Inside incrementByRef: x = " << x << std::endl;
}

// ------------------------------------------------------------------
// Pass by pointer (for comparison)
// ------------------------------------------------------------------
void incrementByPtr(int* x)
{
    ++(*x);
    std::cout << "    Inside incrementByPtr: *x = " << *x << std::endl;
}

// ------------------------------------------------------------------
// Swap using references (cleaner than pointer version)
// ------------------------------------------------------------------
void swapRefs(int& a, int& b)
{
    int temp = a;
    a = b;
    b = temp;
}

// ------------------------------------------------------------------
// const reference: avoids copy without allowing modification
// ------------------------------------------------------------------
void printLargeObject(const std::string& str)
{
    std::cout << "    String (length " << str.size() << "): " << str << std::endl;
    // str += "x";  // ERROR: const reference prevents modification
}

// ------------------------------------------------------------------
// Returning a reference (allows chaining and l-value use)
// ------------------------------------------------------------------
int globalArray[] = {100, 200, 300, 400, 500};

int& getElement(int index)
{
    return globalArray[index];
}

// ------------------------------------------------------------------
// Demonstrating reference in a struct
// ------------------------------------------------------------------
struct Wrapper {
    int& ref;

    // Constructor must initialize reference (references can't be default-constructed)
    Wrapper(int& r) : ref(r) {}
};

int main()
{
    // ------------------------------------------------------------------
    // 1. Basic reference declaration and aliasing
    // ------------------------------------------------------------------
    std::cout << "=== Reference Basics ===" << std::endl;

    int original = 42;
    int& alias = original;      // alias IS original (not a copy)

    std::cout << "  original : " << original << std::endl;
    std::cout << "  alias    : " << alias << std::endl;
    std::cout << "  &original: " << &original << std::endl;
    std::cout << "  &alias   : " << &alias << " (same address!)" << std::endl;

    // Modifying alias modifies original
    alias = 100;
    std::cout << "  After alias = 100:" << std::endl;
    std::cout << "  original : " << original << std::endl;

    // Modifying original is visible through alias
    original = 200;
    std::cout << "  After original = 200:" << std::endl;
    std::cout << "  alias    : " << alias << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 2. References must be initialized and cannot be reseated
    // ------------------------------------------------------------------
    std::cout << "=== References Cannot Be Reseated ===" << std::endl;

    int a = 10, b = 20;
    int& ref = a;

    std::cout << "  ref -> a, a = " << a << std::endl;

    // This does NOT make ref point to b. It copies b's value into a.
    ref = b;
    std::cout << "  After ref = b:" << std::endl;
    std::cout << "  a = " << a << " (a now holds b's value)" << std::endl;
    std::cout << "  b = " << b << " (unchanged)" << std::endl;
    std::cout << "  ref still aliases a: &ref=" << &ref
              << " &a=" << &a << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 3. Pass by value vs reference vs pointer
    // ------------------------------------------------------------------
    std::cout << "=== Pass by Value vs Reference vs Pointer ===" << std::endl;

    int val = 10;

    std::cout << "  Starting value: " << val << std::endl;
    incrementByValue(val);
    std::cout << "  After incrementByValue: val = " << val
              << " (unchanged)" << std::endl;

    incrementByRef(val);
    std::cout << "  After incrementByRef:   val = " << val
              << " (modified!)" << std::endl;

    incrementByPtr(&val);
    std::cout << "  After incrementByPtr:   val = " << val
              << " (modified!)" << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 4. Swap via references
    // ------------------------------------------------------------------
    std::cout << "=== Swap via References ===" << std::endl;

    int x = 10, y = 20;
    std::cout << "  Before: x=" << x << ", y=" << y << std::endl;
    swapRefs(x, y);
    std::cout << "  After:  x=" << x << ", y=" << y << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 5. const reference
    // ------------------------------------------------------------------
    std::cout << "=== const Reference ===" << std::endl;

    // const reference to a variable
    int number = 42;
    const int& cref = number;
    std::cout << "  number = " << number << std::endl;
    std::cout << "  cref   = " << cref << std::endl;
    number = 50;    // OK: modify through original name
    std::cout << "  After number = 50, cref = " << cref << std::endl;
    // cref = 60;   // ERROR: can't modify through const reference

    // const reference can bind to a temporary (extends its lifetime)
    const int& temp = 100 + 200;
    std::cout << "  const int& temp = 100 + 200: " << temp << std::endl;

    // Pass string by const reference (avoids expensive copy)
    std::string longString = "This is a long string that we avoid copying";
    printLargeObject(longString);
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 6. Returning a reference
    // ------------------------------------------------------------------
    std::cout << "=== Returning References ===" << std::endl;

    std::cout << "  globalArray[2] before: " << globalArray[2] << std::endl;

    // getElement returns a reference, so we can assign to it
    getElement(2) = 999;
    std::cout << "  After getElement(2) = 999: " << globalArray[2] << std::endl;

    // Can also read through returned reference
    int& elemRef = getElement(0);
    std::cout << "  elemRef = getElement(0): " << elemRef << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 7. Reference as a struct member
    // ------------------------------------------------------------------
    std::cout << "=== Reference in Struct ===" << std::endl;

    int source = 77;
    Wrapper w(source);

    std::cout << "  source = " << source << std::endl;
    std::cout << "  w.ref  = " << w.ref << std::endl;

    w.ref = 88;
    std::cout << "  After w.ref = 88:" << std::endl;
    std::cout << "  source = " << source << " (modified through struct ref)" << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 8. References vs Pointers summary
    // ------------------------------------------------------------------
    std::cout << "=== References vs Pointers ===" << std::endl;
    std::cout << "  References:" << std::endl;
    std::cout << "    - Must be initialized at declaration" << std::endl;
    std::cout << "    - Cannot be null" << std::endl;
    std::cout << "    - Cannot be reseated to another object" << std::endl;
    std::cout << "    - No explicit dereferencing needed" << std::endl;
    std::cout << "    - Cleaner syntax" << std::endl;
    std::cout << "  Pointers:" << std::endl;
    std::cout << "    - Can be declared without initialization" << std::endl;
    std::cout << "    - Can be null (NULL / 0)" << std::endl;
    std::cout << "    - Can be reassigned to point elsewhere" << std::endl;
    std::cout << "    - Support pointer arithmetic" << std::endl;
    std::cout << "    - Can have pointer-to-pointer" << std::endl;

    return 0;
}

/*
Expected output:

=== Reference Basics ===
  original : 42
  alias    : 42
  &original: 0x7ffd...
  &alias   : 0x7ffd... (same address!)
  After alias = 100:
  original : 100
  After original = 200:
  alias    : 200

=== References Cannot Be Reseated ===
  ref -> a, a = 10
  After ref = b:
  a = 20 (a now holds b's value)
  b = 20 (unchanged)
  ref still aliases a: &ref=0x... &a=0x...

=== Pass by Value vs Reference vs Pointer ===
  Starting value: 10
    Inside incrementByValue: x = 11
  After incrementByValue: val = 10 (unchanged)
    Inside incrementByRef: x = 11
  After incrementByRef:   val = 11 (modified!)
    Inside incrementByPtr: *x = 12
  After incrementByPtr:   val = 12 (modified!)

=== Swap via References ===
  Before: x=10, y=20
  After:  x=20, y=10

=== const Reference ===
  number = 42
  cref   = 42
  After number = 50, cref = 50
  const int& temp = 100 + 200: 300
    String (length 44): This is a long string that we avoid copying

=== Returning References ===
  globalArray[2] before: 300
  After getElement(2) = 999: 999
  elemRef = getElement(0): 100

=== Reference in Struct ===
  source = 77
  w.ref  = 77
  After w.ref = 88:
  source = 88 (modified through struct ref)

=== References vs Pointers ===
  References:
    - Must be initialized at declaration
    - Cannot be null
    - Cannot be reseated to another object
    - No explicit dereferencing needed
    - Cleaner syntax
  Pointers:
    - Can be declared without initialization
    - Can be null (NULL / 0)
    - Can be reassigned to point elsewhere
    - Support pointer arithmetic
    - Can have pointer-to-pointer
*/
Run command
g++ -std=c++98 -Wall -Wextra -o example references.cpp