C++中值传递和引用传递的区别

C++中值传递和引用传递的区别

值传递:在函数调用时,传递的是实际参数的副本,因此函数内对参数的修改不会影响到实际参数。
引用传递:在函数调用时,传递的是实际参数的引用,因此函数内对参数的修改会影响到实际参数。

值传递

示例代码:

class A{
public:
    A() {
        std::cout << "A constructor called" << std::endl;
    }

    A(const A& other) {
        std::cout << "A copy constructor called" << std::endl;
    }

    int a;
};

void func(A a) {
    a.a = 20;
}

int main() {
    A a;
    a.a = 10;
    std::cout << "before func call, a.a = " << a.a << std::endl;
    func(a);
    std::cout << "after func call, a.a = " << a.a << std::endl;
    return 0;
}

输出结果:

//传递的是副本,因此调用了拷贝构造,修改了副本,不会影响到实际参数
A constructor called
before func call, a.a = 10
A copy constructor called    //调用拷贝构造
after func call, a.a = 10

引用传递

示例代码:

class A{
public:
    A() {
        std::cout << "A constructor called" << std::endl;
    }

    A(const A& other) {
        std::cout << "A copy constructor called" << std::endl;
    }

    int a;
};

void func(A& a) {
    a.a = 20;
}

int main() {
    A a;
    a.a = 10;
    std::cout << "before func call, a.a = " << a.a << std::endl;
    func(a);
    std::cout << "after func call, a.a = " << a.a << std::endl;
    return 0;
}

输出结果:

//传递的是引用,因此不会调用拷贝构造,直接修改了实际参数
A constructor called
before func call, a.a = 10      
after func call, a.a = 20

使用场景

从机制上来看,值传递适用于不可变的对象,即你不希望改变原本对象的值,而引用传递适用于可变的对象,即你希望改变原本对象的值。
从性能上考虑,值传递需要拷贝对象,对于简单数据类型,两者区别较小,但对于类、结构体等复杂对象,拷贝过程可能比较耗时,而引用传递不需要拷贝对象,因此在性能上有优势。在使用上应尽可能使用引用传递来减少拷贝的开销。如果你不希望改变原本对象可以通过添加const关键字来实现

拓展

引用可以理解为一个对象的别名(底层应该是通过指针常量实现的,这个博主不太确定),因此引用在初始化时就必须绑定(先有对象存在,才能给对象起别名),而且绑定之后不能再改变。

示例代码:

class A{
public:
    A() {
        std::cout << "A constructor called" << std::endl;
    }

    A(const A& other) {
        std::cout << "A copy constructor called" << std::endl;
    }

    A& operator=(const A& other) {
        std::cout << "A copy assignment operator called" << std::endl;
        return *this;
    }

    int a;
};

void func(A& a) {
    A b;
    b.a = 20;
    A& ref_b = b;

    //一样的效果
    a = ref_b;
    //a = static_cast<A&>(ref_b);

    std::cout << "func ptr a = " << &a << std::endl;
    std::cout << "func ptr b = " << &b << std::endl;
}

int main() {
    A a;
    a.a = 10;
    std::cout << "main ptr a = " << &a << std::endl;
    std::cout << "before func call, a.a = " << a.a << std::endl;
    func(a);
    std::cout << "after func call, a.a = " << a.a << std::endl;
    return 0;
}

输出结果:

//地址不一致,实际调用的是赋值运算符
A constructor called
main ptr a = 0000007B772FFC14
before func call, a.a = 10
A constructor called
A copy assignment operator called
func ptr a = 0000007B772FFC14
func ptr b = 0000007B772FFAD4
after func call, a.a = 10
posted @   xiaodao0036  阅读(33)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示