C++的参数传递可以分为值传递、指针传递和引用传递三种:
函数参数传递方式 | 其它称呼 | 实参 | 形参 | 本质 |
值传递 | 传值 | 普通变量 | 普通变量 | 普通变量传递数值 |
指针传递 | 传地址(传址) | 普通变量 | 指针变量 | 普通变量传递地址 |
引用传递 | 传引用 | 引用变量 | 引用变量 | 普通变量传递引用 |
值传递
介绍:
形参是实参的拷贝,改变形参的值并不会影响外部实参的值。从被调用函数的角度来说,值传递是单向的(实参->形参),赋值完毕后实参就和形参没有任何联系。
应用场景:
当函数内部需要修改参数,并且不希望这个改变影响调用者时,采用值传递。
值传递最常见的应用场景就是传递基本数据类型(int,float等),小型结构体,枚举类型等。
值传递--基本数据类型
#include<stdio.h>
void printValue(int value)
{
std::cout << "The value is: " << value << std::endl;
}
int main()
{
int value = 10;
printValue(value);
return 0;
}
值传递--类对象
注意:
1. 有一次拷贝构造函数,还默认有一次string的拷贝构造函数,如果对象较大时,内存消耗较大
2.值没有发生改变,并没有更新年龄。
值传递的缺点:
〇 值传递只是复制变量的值,在函数内部对参数的任何修改都不会影响原变量的值,不可以用来改变实参;〇 对于大型对象,值传递会导致内存消耗较大,因此可以使用C++ 的引用传递或指针传递来避免这种消耗。
指针传递
原理:
当使用指针传递参数时,实际上是将指针作为参数传递给函数。指针是一个变量,它存储了一个内存地址,该地址指向另一个变量的位置。因此,使用指针传递参数时,实际上传递的是变量所在的内存地址,而不是变量本身。
应用场景:
在函数中,可以通过指针访问所指向的内存位置的值,并对其进行修改。这样一来,函数可以访问或修改函数外部的变量。
指针传递--数组
指针传递--结构体
指针传递--类对象
举例:
指针传递传递的缺点:
容易出现空指针和野指针:
由于指针不一定总是指向有效的内存,所以在使用指针传递时,需要保证指针是有效的,否则程序会出现崩溃或者未定义的行为。
容易出现内存泄漏和内存破坏:
在使用指针传递时,需要注意内存的生命周期和内存的所有权,如果不注意管理内存,则容易出现内存泄漏和内存破坏的情况。
可读性差:
使用指针传递时,需要读取指针所指向的内存的值,而不是直接使用变量名来读取变量的值,这会降低代码的可读性。
容易出现别名问题:
使用指针传递时,如果多个指针指向同一个内存位置,可能会出现别名问题,即多个指针可以通过不同的方式修改同一个变量的值,导致程序出现意外的结果。
总之,指针传递需要谨慎使用,并且需要遵循一些编码规范和最佳实践,以避免出现上述问题
引用传递
引用是一个别名
在 C++ 中,引用是一个别名,它可以与某个对象绑定在一起。变量名是该变量的符号名称,而引用是该变量的另一个符号名称。也就是说,引用所指向的变量与引用本身是同一个变量,它们共享同一个内存地址。
引用传递只是一种复制地址的方式
在函数调用中,使用引用传递参数,实际上传递的是变量的内存地址,而不是变量本身。因此,使用引用传递参数时,函数可以通过引用访问或修改函数外部的变量,因为引用所指向的变量与函数外部的变量是同一个变量。
引用传递可以避免不必要的内存拷贝
与传值方式不同,使用引用传递参数可以避免不必要的内存拷贝,从而提高程序的性能。
总之,引用传递是一种非常常用的参数传递方式,它可以通过别名来访问或修改函数外部的变量。在使用引用传递时,需要注意引用的有效性和内存的所有权,以避免出现问题。
按常量引用传参
思考:我们之前说了,如果想要对传入参数进行一些修改,我们要使用引用传参,那么我们不想要对传入参数进行修改,是不是就只能使用按值传参了呢?我们能不能既拥有引用的节省拷贝开支的优点,又拥有按值传参的不影响原值的优点呢?
于是,按常量引用传参也就应运而生了。如果我们只是想要看一看参数的值,而并不需要去修改它,我们就可以使用按常量引用传值,从而减少拷贝方面的开销。
引用传递和指针传递相同点和不同点
不同数据类型常用的传参方式
数据类型 | 传参方式 |
布尔类型、字符类型和短整型(short) | 适合按值传递,因为它们占用的内存较小。 |
整型类型(int、long、long long) | 一般可以按值或按引用传递,因为它们占用的内存较小,如果需要修改参数的值,建议使用按引用传递 |
浮点类型(float、double、long double) | 建议按引用传递,因为它们比较大,复制成本较高,同时也可以避免由于浮点数相加、相减等运算产生的精度误差 |
自定义类型(结构体、类等) | 建议按引用传递,因为自定义类型可能比较复杂,复制成本较高,同时按引用传递可以避免产生副本,提高效率。如果只需要读取参数的值,也可以使用按值传递,或者是常量引用方式 |