cpp
examples
examples.cpp⚙️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;
}