理解C++引用名及变量传入

目录

引用名

1. 别名机制

2. 避免拷贝

3. 支持操作符重载

4. 支持函数返回引用

参数传入的方式

1、值传递

2、引用传递

3、指针传递


引用名

在C++中,引用允许一个变量名(我们称之为“引用名”)作为另一个变量(我们称之为“被引用的变量”或“原始变量”)的别名。这意味着通过引用名,我们可以直接访问和修改被引用变量的值,而不需要使用指针和解引用操作。

#include <iostream>  
  
int main() {  
    int originalVariable = 10; // 原始变量  
    int& referenceName = originalVariable; // 引用名,作为originalVariable的别名  
  
    // 通过引用名访问和修改原始变量的值  
    std::cout << "原始变量的值: " << originalVariable << std::endl; // 输出: 原始变量的值: 10  
    std::cout << "通过引用名访问的值: " << referenceName << std::endl; // 输出: 通过引用名访问的值: 10  
  
    referenceName = 20; // 修改引用名指向的值,实际上修改了原始变量的值  
  
    std::cout << "修改后原始变量的值: " << originalVariable << std::endl; // 输出: 修改后原始变量的值: 20  
    std::cout << "修改后通过引用名访问的值: " << referenceName << std::endl; // 输出: 修改后通过引用名访问的值: 20  
  
    return 0;  
}

1. 别名机制

:假设我们有一个整数变量int a = 10;,我们想要通过另一个名字来操作这个变量,但又不想使用指针。这时,我们可以使用引用来实现。

int a = 10;  
int& b = a; // b是a的引用,即别名  
b = 20; // 现在a的值也变成了20  
std::cout << a << std::endl; // 输出: 20

2. 避免拷贝

:考虑一个大型对象(比如一个包含大量数据的结构体或类),当我们需要将其作为参数传递给函数时,如果直接传递对象本身,则会发生拷贝,这可能会非常耗时和占用大量内存。使用引用可以避免这种情况。

class LargeObject {  
    // 假设这里有很多数据成员  
public:  
    void doSomething() { /* ... */ }  
};  
  
void processLargeObject(LargeObject& obj) { // 使用引用  
    obj.doSomething(); // 直接在原始对象上操作  
}  
  
int main() {  
    LargeObject obj;  
    processLargeObject(obj); // 传递引用,避免拷贝  
    return 0;  
}

3. 支持操作符重载

:在自定义类中,我们经常需要重载操作符来让对象的使用更加直观。在这些重载函数中,使用引用来作为参数可以让我们能够直接修改操作数。

class Vector2D {  
public:  
    float x, y;  
  
    // 重载加法操作符  
    Vector2D& operator+=(const Vector2D& other) {  
        x += other.x;  
        y += other.y;  
        return *this; // 返回对自身的引用,支持链式调用  
    }  
};  
  
int main() {  
    Vector2D v1{1.0, 2.0}, v2{3.0, 4.0};  
    v1 += v2; // 使用+=操作符,直接修改v1  
    return 0;  
}

4. 支持函数返回引用

:在某些情况下,我们需要从函数中返回一个对象内部成员的引用,以便调用者能够直接访问或修改这些数据。

class Matrix {  
private:  
    std::vector<std::vector<int>> data;  
public:  
    // 假设有一个函数返回矩阵中某一行的引用  
    std::vector<int>& getRow(int rowIndex) {  
        return data[rowIndex]; // 返回对内部向量的引用  
    }  
};  
  
int main() {  
    Matrix matrix(10, std::vector<int>(10, 0)); // 假设Matrix有这样一个构造函数  
    matrix.getRow(0)[0] = 1; // 直接修改矩阵第一行第一列的值  
    return 0;  
}

参数传入的方式

1. 值传递

优点:保护原始数据不被修改,函数内部的操作不会影响外部变量。

缺点:对于大型对象,值传递可能导致不必要的拷贝,影响性能。

适用于不需要修改原始数据,且参数对象较小的情况。

#include <iostream>  
  
void modifyValue(int x) {  
    // 尝试修改x的值,但这只会影响x的副本,不会影响原始数据  
    x = 10;  
}  
  
int main() {  
    int originalValue = 5;  
    std::cout << "Before modification: " << originalValue << std::endl; // 输出: Before modification: 5  
  
    modifyValue(originalValue); // 调用函数,传递的是originalValue的副本  
  
    std::cout << "After modification: " << originalValue << std::endl; // 输出: After modification: 5,原始值未变  
  
    return 0;  
}

2. 引用传递

优点:避免拷贝,提高效率;可以直接修改原始数据(对于非常量引用)。

缺点:可能意外修改原始数据(对于非常量引用),需要谨慎使用。

常量引用:适用于需要读取但不修改原始数据,且参数对象较大的情况。

#include <iostream>  
  
void printValue(const int& ref) {  
    // 尝试修改ref的值,但这里会编译失败,因为ref是常量引用  
    // ref = 10; // 编译错误  
    std::cout << "Value: " << ref << std::endl;  
}  
  
int main() {  
    int originalValue = 5;  
    printValue(originalValue); // 调用函数,传递的是originalValue的引用,但因为是常量引用,所以不能修改  
    // originalValue的值保持不变  
  
    return 0;  
}

非常量引用:适用于需要修改原始数据的情况。

#include <iostream>  
  
void modifyValue(int& ref) {  
    // 修改ref的值,这会直接影响到原始数据  
    ref = 10;  
}  
  
int main() {  
    int originalValue = 5;  
    std::cout << "Before modification: " << originalValue << std::endl; // 输出: Before modification: 5  
  
    modifyValue(originalValue); // 调用函数,传递的是originalValue的引用  
  
    std::cout << "After modification: " << originalValue << std::endl; // 输出: After modification: 10,原始值被修改  
  
    return 0;  
}

3. 指针传递

优点:与引用传递类似,避免拷贝,提高效率;可以传递空指针;可以动态改变指针的指向。

缺点:需要手动解引用指针,增加了代码的复杂性;需要处理空指针的情况。

常量指针:指向常量的指针意味着你不能通过这个指针来修改它所指向的数据。

#include <iostream>  
  
void printValue(const int* ptr) {  
    // 因为ptr是指向常量的指针,所以我们不能通过*ptr来修改值  
    std::cout << "Value: " << *ptr << std::endl;  
    // 下面的代码会导致编译错误,因为不能修改const指针指向的值  
    // *ptr = 10; // 错误:不能给常量赋值  
}  
  
int main() {  
    int value = 5;  
    const int* ptr = &value; // 注意:这里ptr是指向常量的指针,但value本身不是常量  
    printValue(ptr); // 输出: Value: 5  
  
    // 注意:虽然value本身不是const,但我们不能通过ptr来修改它  
    // 因为ptr被声明为指向const int的指针  
  
    return 0;  
}

非常量指针

指向非常量的指针允许你通过指针来修改它所指向的数据。

#include <iostream>  
  
void modifyValue(int* ptr) {  
    // 因为ptr不是指向常量的指针,所以我们可以通过*ptr来修改值  
    *ptr = 10;  
}  
  
int main() {  
    int value = 5;  
    int* ptr = &value; // ptr是指向非常量的指针  
    std::cout << "Before modification: " << value << std::endl; // 输出: Before modification: 5  
  
    modifyValue(ptr); // 调用函数来修改值  
  
    std::cout << "After modification: " << value << std::endl; // 输出: After modification: 10  
  
    return 0;  
}

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值