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