Skip to content

C++ 引用

概述

引用(Reference)是C++中的一个重要特性,它为已存在的变量提供了一个别名。引用本质上是对象的另一个名字,通过引用可以直接操作原始对象。引用提供了比指针更安全、更直观的间接访问方式,是现代C++编程的重要工具。

🔗 引用基础

引用的声明和初始化

cpp
#include <iostream>

int main() {
    std::cout << "=== 引用基础 ===" << std::endl;
    
    // 1. 基本引用声明
    int original = 42;
    int& ref = original;  // ref是original的引用(别名)
    
    std::cout << "原变量值: " << original << std::endl;
    std::cout << "引用值: " << ref << std::endl;
    std::cout << "原变量地址: " << &original << std::endl;
    std::cout << "引用地址: " << &ref << std::endl;
    
    // 2. 通过引用修改原变量
    ref = 100;
    std::cout << "通过引用修改后:" << std::endl;
    std::cout << "原变量值: " << original << std::endl;
    std::cout << "引用值: " << ref << std::endl;
    
    // 3. 引用必须初始化
    // int& bad_ref;  // 错误!引用必须初始化
    
    // 4. 引用不能重新绑定
    int another = 200;
    // ref = another;  // 这是赋值,不是重新绑定
    ref = another;     // 将another的值赋给original
    std::cout << "赋值后original: " << original << std::endl;
    
    return 0;
}

引用 vs 指针

cpp
#include <iostream>

int main() {
    std::cout << "=== 引用 vs 指针 ===" << std::endl;
    
    int value = 42;
    
    // 引用方式
    int& ref = value;
    
    // 指针方式
    int* ptr = &value;
    
    std::cout << "原始值: " << value << std::endl;
    
    // 修改值
    ref = 100;        // 直接赋值
    std::cout << "通过引用修改: " << value << std::endl;
    
    *ptr = 200;       // 需要解引用
    std::cout << "通过指针修改: " << value << std::endl;
    
    // 语法比较
    std::cout << "\n语法比较:" << std::endl;
    std::cout << "引用访问: " << ref << std::endl;
    std::cout << "指针访问: " << *ptr << std::endl;
    
    // 引用的优势
    std::cout << "\n引用优势:" << std::endl;
    std::cout << "1. 语法简洁,不需要解引用" << std::endl;
    std::cout << "2. 不能为空,更安全" << std::endl;
    std::cout << "3. 不能重新绑定,避免错误" << std::endl;
    std::cout << "4. 没有指针算术运算" << std::endl;
    
    return 0;
}

📋 const引用

const引用的使用

cpp
#include <iostream>
#include <string>

int main() {
    std::cout << "=== const引用 ===" << std::endl;
    
    // 1. const引用绑定到变量
    int value = 42;
    const int& const_ref = value;
    
    std::cout << "const引用值: " << const_ref << std::endl;
    // const_ref = 100;  // 错误!不能通过const引用修改值
    
    value = 100;  // 可以直接修改原变量
    std::cout << "修改原变量后const引用值: " << const_ref << std::endl;
    
    // 2. const引用绑定到字面量
    const int& literal_ref = 50;  // 绑定到临时对象
    const std::string& str_ref = "Hello World";
    
    std::cout << "字面量引用: " << literal_ref << std::endl;
    std::cout << "字符串引用: " << str_ref << std::endl;
    
    // 3. const引用绑定到表达式结果
    int a = 10, b = 20;
    const int& expr_ref = a + b;  // 绑定到临时对象
    
    std::cout << "表达式引用: " << expr_ref << std::endl;
    
    return 0;
}

const引用作为函数参数

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

// 使用const引用避免拷贝,同时保证不修改参数
void printString(const std::string& str) {
    std::cout << "字符串: " << str << std::endl;
    // str += "!";  // 错误!不能修改const引用
}

void printVector(const std::vector<int>& vec) {
    std::cout << "向量元素: ";
    for (const int& element : vec) {
        std::cout << element << " ";
    }
    std::cout << std::endl;
}

// 计算字符串长度(不修改原字符串)
size_t getStringLength(const std::string& str) {
    return str.length();
}

// 查找最大值(不修改原数组)
int findMax(const std::vector<int>& numbers) {
    int max_val = numbers[0];
    for (const int& num : numbers) {
        if (num > max_val) {
            max_val = num;
        }
    }
    return max_val;
}

int main() {
    std::cout << "=== const引用作为函数参数 ===" << std::endl;
    
    // 字符串示例
    std::string message = "Hello C++";
    printString(message);
    printString("Literal String");  // 可以传递字面量
    
    size_t len = getStringLength(message);
    std::cout << "字符串长度: " << len << std::endl;
    
    // 向量示例
    std::vector<int> numbers = {5, 2, 8, 1, 9, 3};
    printVector(numbers);
    
    int max_num = findMax(numbers);
    std::cout << "最大值: " << max_num << std::endl;
    
    return 0;
}

🔄 引用作为函数返回值

返回引用的函数

cpp
#include <iostream>
#include <vector>

class NumberContainer {
private:
    std::vector<int> numbers_;
    
public:
    NumberContainer(std::initializer_list<int> init) : numbers_(init) {}
    
    // 返回引用,允许修改
    int& at(size_t index) {
        if (index >= numbers_.size()) {
            throw std::out_of_range("索引越界");
        }
        return numbers_[index];
    }
    
    // const版本,返回const引用
    const int& at(size_t index) const {
        if (index >= numbers_.size()) {
            throw std::out_of_range("索引越界");
        }
        return numbers_[index];
    }
    
    size_t size() const { return numbers_.size(); }
    
    void print() const {
        for (const int& num : numbers_) {
            std::cout << num << " ";
        }
        std::cout << std::endl;
    }
};

// 返回两个数中较大者的引用
int& max(int& a, int& b) {
    return (a > b) ? a : b;
}

int main() {
    std::cout << "=== 引用作为返回值 ===" << std::endl;
    
    // 1. 容器引用返回
    NumberContainer container{10, 20, 30, 40, 50};
    
    std::cout << "原始容器: ";
    container.print();
    
    // 通过引用修改元素
    container.at(2) = 300;
    std::cout << "修改后: ";
    container.print();
    
    // 2. 选择性修改
    int x = 15, y = 25;
    std::cout << "x = " << x << ", y = " << y << std::endl;
    
    max(x, y) = 100;  // 修改较大者
    std::cout << "修改较大者后: x = " << x << ", y = " << y << std::endl;
    
    // 3. const对象使用const引用
    const NumberContainer const_container{1, 2, 3};
    std::cout << "const容器第一个元素: " << const_container.at(0) << std::endl;
    // const_container.at(0) = 10;  // 错误!不能修改const引用
    
    return 0;
}

危险的引用返回

cpp
#include <iostream>

// 危险:返回局部变量的引用
int& dangerousFunction() {
    int local = 42;
    return local;  // 危险!返回局部变量的引用
}

// 安全:返回参数的引用
int& safeFunction(int& param) {
    return param;  // 安全,param来自外部
}

// 安全:返回成员变量的引用
class SafeClass {
private:
    int member_;
    
public:
    SafeClass(int value) : member_(value) {}
    
    int& getMember() {
        return member_;  // 安全,返回成员变量
    }
};

int main() {
    std::cout << "=== 引用返回的安全性 ===" << std::endl;
    
    // 危险示例(不要这样做)
    std::cout << "危险示例(仅作演示):" << std::endl;
    // int& dangerous_ref = dangerousFunction();  // 悬挂引用
    // std::cout << dangerous_ref << std::endl;   // 未定义行为
    
    // 安全示例
    int value = 100;
    int& safe_ref = safeFunction(value);
    std::cout << "安全引用: " << safe_ref << std::endl;
    
    safe_ref = 200;
    std::cout << "修改后: " << value << std::endl;
    
    // 成员变量引用
    SafeClass obj(300);
    int& member_ref = obj.getMember();
    std::cout << "成员引用: " << member_ref << std::endl;
    
    member_ref = 400;
    std::cout << "修改成员后: " << obj.getMember() << std::endl;
    
    return 0;
}

🎯 引用的高级应用

引用与函数重载

cpp
#include <iostream>

class Processor {
public:
    // 处理可修改对象
    void process(int& value) {
        value *= 2;
        std::cout << "处理可修改引用: " << value << std::endl;
    }
    
    // 处理只读对象
    void process(const int& value) {
        std::cout << "处理只读引用: " << value << std::endl;
    }
};

// 完美转发示例(C++11)
template<typename T>
void forwardToProcess(T&& arg) {
    Processor proc;
    proc.process(std::forward<T>(arg));
}

int main() {
    std::cout << "=== 引用与函数重载 ===" << std::endl;
    
    Processor proc;
    
    // 可修改对象
    int mutable_var = 10;
    std::cout << "调用前: " << mutable_var << std::endl;
    proc.process(mutable_var);
    std::cout << "调用后: " << mutable_var << std::endl;
    
    // 只读对象
    const int const_var = 20;
    proc.process(const_var);
    
    // 临时对象
    proc.process(30);
    
    // 完美转发
    std::cout << "\n完美转发示例:" << std::endl;
    int value = 50;
    forwardToProcess(value);         // 左值
    forwardToProcess(60);           // 右值
    
    return 0;
}

引用数组和引用的引用

cpp
#include <iostream>

int main() {
    std::cout << "=== 引用的限制 ===" << std::endl;
    
    // 1. 引用数组(不存在)
    // int& ref_array[3];  // 错误!不能创建引用的数组
    
    // 但可以创建数组的引用
    int arr[3] = {1, 2, 3};
    int (&array_ref)[3] = arr;  // 数组的引用
    
    std::cout << "数组引用: ";
    for (int i = 0; i < 3; i++) {
        std::cout << array_ref[i] << " ";
    }
    std::cout << std::endl;
    
    // 2. 引用的引用(需要类型推导)
    int value = 42;
    int& ref1 = value;
    
    // int& & ref2 = ref1;  // 错误!不能直接声明引用的引用
    
    // 但在模板中可能出现引用折叠
    auto& ref2 = ref1;  // ref2也是int&类型
    std::cout << "引用的引用: " << ref2 << std::endl;
    
    // 3. 指向引用的指针(不存在)
    // int&* ptr_to_ref;  // 错误!不能创建指向引用的指针
    
    // 但可以创建引用到指针
    int* ptr = &value;
    int*& ref_to_ptr = ptr;  // 指针的引用
    
    std::cout << "指针引用指向的值: " << *ref_to_ptr << std::endl;
    
    return 0;
}

📚 实际应用示例

链表节点操作

cpp
#include <iostream>

struct ListNode {
    int data;
    ListNode* next;
    
    ListNode(int value) : data(value), next(nullptr) {}
};

class SimpleList {
private:
    ListNode* head_;
    
public:
    SimpleList() : head_(nullptr) {}
    
    ~SimpleList() {
        while (head_) {
            ListNode* temp = head_;
            head_ = head_->next;
            delete temp;
        }
    }
    
    void insert(int value) {
        ListNode* new_node = new ListNode(value);
        new_node->next = head_;
        head_ = new_node;
    }
    
    // 返回引用允许修改
    int& at(int index) {
        ListNode* current = head_;
        for (int i = 0; i < index && current; i++) {
            current = current->next;
        }
        if (!current) {
            throw std::out_of_range("索引越界");
        }
        return current->data;
    }
    
    void print() const {
        ListNode* current = head_;
        std::cout << "链表: ";
        while (current) {
            std::cout << current->data << " ";
            current = current->next;
        }
        std::cout << std::endl;
    }
};

int main() {
    std::cout << "=== 链表引用应用 ===" << std::endl;
    
    SimpleList list;
    list.insert(10);
    list.insert(20);
    list.insert(30);
    
    list.print();
    
    // 通过引用修改节点数据
    list.at(1) = 200;
    std::cout << "修改索引1后: ";
    list.print();
    
    return 0;
}

📋 引用最佳实践

引用使用指南

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

// 最佳实践示例
class BestPractices {
public:
    // 1. 传递大对象使用const引用
    static void processLargeObject(const std::vector<std::string>& data) {
        std::cout << "处理 " << data.size() << " 个字符串" << std::endl;
    }
    
    // 2. 需要修改参数时使用非const引用
    static void modifyString(std::string& str) {
        str += " - 已修改";
    }
    
    // 3. 简单类型可以按值传递
    static int addNumbers(int a, int b) {  // 不需要引用
        return a + b;
    }
    
    // 4. 返回引用用于链式调用
    BestPractices& setValue(int value) {
        value_ = value;
        return *this;  // 返回自身引用
    }
    
    BestPractices& multiply(int factor) {
        value_ *= factor;
        return *this;
    }
    
    int getValue() const { return value_; }
    
private:
    int value_ = 0;
};

int main() {
    std::cout << "=== 引用最佳实践 ===" << std::endl;
    
    // 1. 处理大对象
    std::vector<std::string> large_data = {
        "字符串1", "字符串2", "字符串3", "字符串4"
    };
    BestPractices::processLargeObject(large_data);
    
    // 2. 修改参数
    std::string message = "原始消息";
    std::cout << "修改前: " << message << std::endl;
    BestPractices::modifyString(message);
    std::cout << "修改后: " << message << std::endl;
    
    // 3. 链式调用
    BestPractices obj;
    obj.setValue(10).multiply(3).multiply(2);
    std::cout << "链式调用结果: " << obj.getValue() << std::endl;
    
    // 4. 使用指南
    std::cout << "\n引用使用指南:" << std::endl;
    std::cout << "✓ 传递大对象时使用const引用" << std::endl;
    std::cout << "✓ 需要修改参数时使用引用" << std::endl;
    std::cout << "✓ 返回引用实现链式调用" << std::endl;
    std::cout << "✓ 简单类型按值传递" << std::endl;
    std::cout << "✗ 避免返回局部变量的引用" << std::endl;
    std::cout << "✗ 不要创建空引用" << std::endl;
    
    return 0;
}

总结

引用是C++提供的重要特性,为间接访问提供了安全高效的方式:

核心特点

  • 别名机制:引用是对象的另一个名字
  • 必须初始化:声明时必须绑定到对象
  • 不能重绑定:一旦绑定无法改变
  • 无空引用:比指针更安全

使用场景

场景推荐做法原因
函数参数const引用避免拷贝,保证安全
函数返回引用(谨慎)支持链式调用
容器访问引用允许就地修改
简单类型按值传递性能更好

最佳实践

  • 传递大对象使用const引用
  • 需要修改时使用非const引用
  • 避免返回局部变量引用
  • 优先使用引用而非指针
  • 合理使用const保证安全性

引用让C++代码更加简洁和安全,是现代C++编程不可缺少的工具。

本站内容仅供学习和研究使用。