C++函数形参为引用类型时,传入的参数类型为什么用引用对象的类型和引用类型都可以?
代码如下:
1 | void refer1(int &); |
这里的refer1的形参是一个int类型的引用,但是我传a(int类型)进去可以,我传b(int引用类型)进去也可以,对比refer2的形参,要求传int指针类型,也就是可以传c进去,如果我传a(c指向的类型)进去则报错。
按照常理说应该是类型匹配才对,int 匹配传进来的int,int *匹配传进来的int *,为什么形参是引用int &,既可以是int &又可以是int呢?
如果说形参是引用int &,传 int 进去是为了绑定到实参上,那传一个已经绑定的int &进去是绑定什么呢?
解答:
使用指针或者引用作为形参是为了解决按值传递可能导致的问题。
所以这里再次讲一下使用指针,引用和值作为形参所导致的结果。
C++教科书都会用一个交换两个变量的值的函数来举例:
1 | void swap(int a, int b); //使用指针和引用的情况下形参类型分别为int*和int& |
结果是怎么样的题主应该清楚:按值传递无法完成这一行为,而传递指针或者引用是可行的。
那么原因是什么?
在按值传递的情况下:
1 | int x = 4, y = 5; |
第一步:编译器会在内存开辟两个能存放int型变量的区域(假设分别为0xAAAAAAAA和0xBBBBBBBB),用于保存x和y的值。第二步:swap函数接收x和y的值,编译器会另外开辟两个存放int型变量的区域(假设分别为0xCCCCCCCC和0xDDDDDDDD),将4和5分别赋给形参a和b。第三步:swap函数完成交换,此时形参a=5, b=4,但是实参x和y的值并没有发生变化。因为swap函数只交换了0xCCCCCCCC和0xDDDDDDDD两块区域储存的值,并没有影响到0xAAAAAAAA和0xBBBBBBBB。所以x和y本身没有受到swap函数的影响,交换失败。
形参为指针的情况下:
1 | int x = 4, y = 5; |
第一步:编译器会在内存开辟两个能存放int型变量的区域(假设分别为0xAAAAAAAA和0xBBBBBBBB),用于保存x和y的值。
第二步:编译器会在内存开辟两个能存放int型指针的区域(假设分别为0xCCCCCCCC和0xDDDDDDDD),两块区域分别存储x和y的地址(即0xAAAAAAAA和0xBBBBBBBB)
第三步:swap函数接收px和py的值,编译器会另外开辟两个存放int型指针的区域(假设分别为0xEEEEEEEE和0xFFFFFFFF),将0xAAAAAAAA和0xBBBBBBBB分别赋给形参a和b。
第四步:swap函数创造一个int型变量temp,假设地址为0xGGGGGGGG。
-—————————————————————————————————————————————–
第五步:
1 | temp = *a; |
*a的值就是x的值(即4),temp获得4这个值。
-—————————————————————————————————————————————–
第六步:
1 | *a = *b; |
形参a的值是0xAAAAAAAA,所以这一句将0xAAAAAAAA这一块内存所存储的值由4修改为5,而0xAAAAAAAA正是x的地址。也就是说x本身的值被改成了5。
-—————————————————————————————————————————————–
第七步:
1 | *b = temp; |
同理,形参b的值是0xBBBBBBBB,这一句将0xBBBBBBBB这一块内存所存储的值由5修改为4,而0xBBBBBBBB正是y的地址。也就是说y本身的值被改成了4。
swap函数执行完毕后x和y的值分别为5和4,交换成功。
在这种情况下,如果传入两个int型变量而不是int型指针,则编译不会通过。因为int型变量并不是地址,在a为int型变量的情况下,a并不是符号的合法用途。
-—————————————————————————————————————————————–
形参为引用的情况下:
1 | int x = 4, y = 5; |
第一步:编译器会在内存开辟两个能存放int型变量的区域(假设分别为0xAAAAAAAA和0xBBBBBBBB),用于保存x和y的值。
第二步:两个int型参数传入swap函数,函数将形参a和b分别声明为x和y的引用。此时a的地址和x一样是0xAAAAAAAA,b的地址和y一样是0xBBBBBBBB。
第三步:此时swap函数交换a和b的值,由于a和b的地址分别与x和y的地址相同(即0xAAAAAAAA和0xBBBBBBBB),该函数完成了对x和y的值的交换。交换后0xAAAAAAAA存储的值为5,0xBBBBBBBB存储的值为4。
当形参类型为引用时,实参和形参共享一个地址,对形参的修改也就是对实参的修改。
可以看到,使用指针和引用分别实现交换变量值的机制是不同的。尽管两种方法都直接对x和y的地址储存的值进行了修改,但是当形参是指针时,a和b的值并未发生变化(依然分别是x和y的地址);而当形参是引用时,a和b的值发生了变化。
-—————————————————————————————————————————————–
最后回到问题本身:
为什么形参是引用int &,既可以是int &又可以是int呢?
举个例子:
1 |
|
在这个例子中,rarb的结果和ab完全一致,尽管ra和rb是指向int型变量的引用,但是ra和rb在被声明为引用以后也可以被当作int型变量进行处理。而pa和pb是指向int型变量的指针,它们存储的是a和b的地址而不是a和b的值,所以对pa和pb进行int型变量的运算是非法的。
-—————————————————————————————————————————————–
如果说形参是引用int &,传int进去是为了绑定到实参上,那传一个已经绑定的int &进去是绑定什么呢?
修改一下上面的例子:
1 |
|
在这个例子中,rra为指向【指向int型变量的引用】的引用,国内的C++教科书在讲到引用也会提一下指向引用的引用是合法的。在这种情况下,ra被引用是会被当作普通的int型变量处理。
当一个int&参数传入swap函数的时候,同样地,该int&参数会被当作一个int型变量,然后形参就是这个变量的引用。所以在这种情况下传入int或int&的输出都是一样的。