Sag*_*tic 51 c++ reference-parameters
我试图了解如何使用参考参数.我的文本中有几个例子,但是它们太复杂了我无法理解为什么以及如何使用它们.
你想如何以及为什么要使用参考?如果您没有将参数作为参考,而是将其&
关闭,会发生什么?
例如,这些功能之间的区别是什么:
int doSomething(int& a, int& b);
int doSomething(int a, int b);
Run Code Online (Sandbox Code Playgroud)
我知道引用变量用于更改形式 - >引用,然后允许参数的双向交换.然而,这是我的知识范围,更具体的例子会有很大帮助.
GMa*_*ckG 115
将引用视为别名.当您在引用上调用某些内容时,您实际上是在引用所引用的对象上调用它.
int i;
int& j = i; // j is an alias to i
j = 5; // same as i = 5
Run Code Online (Sandbox Code Playgroud)
在功能方面,请考虑:
void foo(int i)
{
i = 5;
}
Run Code Online (Sandbox Code Playgroud)
上面int i
是一个值,传递的参数是按值传递的.这意味着如果我们说:
int x = 2;
foo(x);
Run Code Online (Sandbox Code Playgroud)
i
将是一个复制的x
.因此设置i
为5对此没有影响x
,因为它是x
被更改的副本.但是,如果我们i
提供参考:
void foo(int& i) // i is an alias for a variable
{
i = 5;
}
Run Code Online (Sandbox Code Playgroud)
然后说foo(x)
不再复制x
; i
是 x
.因此,如果我们说foo(x)
,在函数内部i = 5;
完全相同x = 5;
,并且x
更改.
希望这有点澄清.
为什么这很重要?编程时,您永远不想复制和粘贴代码.你想创建一个完成一项任务的功能,并且它做得很好.只要需要执行该任务,就可以使用该功能.
所以我们假设我们要交换两个变量.看起来像这样:
int x, y;
// swap:
int temp = x; // store the value of x
x = y; // make x equal to y
y = temp; // make y equal to the old value of x
Run Code Online (Sandbox Code Playgroud)
好,太棒了.我们想让它成为一个函数,因为:swap(x, y);
更容易阅读.那么,让我们试试这个:
void swap(int x, int y)
{
int temp = x;
x = y;
y = temp;
}
Run Code Online (Sandbox Code Playgroud)
这不行!问题是这是交换两个变量的副本.那是:
int a, b;
swap(a, b); // hm, x and y are copies of a and b...a and b remain unchanged
Run Code Online (Sandbox Code Playgroud)
在C中,不存在引用,解决方案是传递这些变量的地址; 也就是说,使用指针*:
void swap(int* x, int* y)
{
int temp = *x;
*x = *y;
*y = temp;
}
int a, b;
swap(&a, &b);
Run Code Online (Sandbox Code Playgroud)
这很好用.但是,它使用起来有点笨拙,实际上有点不安全.swap(nullptr, nullptr)
,交换两个nothings和dereferences null指针...未定义的行为!可通过一些检查修复:
void swap(int* x, int* y)
{
if (x == nullptr || y == nullptr)
return; // one is null; this is a meaningless operation
int temp = *x;
*x = *y;
*y = temp;
}
Run Code Online (Sandbox Code Playgroud)
但看起来我们的代码有多笨拙.C++引入了引用来解决这个问题.如果我们可以为变量添加别名,我们将获得我们正在寻找的代码:
void swap(int& x, int& y)
{
int temp = x;
x = y;
y = temp;
}
int a, b;
swap(a, b); // inside, x and y are really a and b
Run Code Online (Sandbox Code Playgroud)
既易于使用又安全.(我们不能意外地传入null,没有空引用.)这是有效的,因为函数内部发生的交换实际上发生在函数外的别名变量上.
(注意,永远不要写一个swap
函数.:)标题中已经存在一个<algorithm>
,并且模板适用于任何类型.)
另一个用途是删除调用函数时发生的副本.考虑一下我们的数据类型非常大.复制此对象需要花费大量时间,我们希望避免这种情况:
struct big_data
{ char data[9999999]; }; // big!
void do_something(big_data data);
big_data d;
do_something(d); // ouch, making a copy of all that data :<
Run Code Online (Sandbox Code Playgroud)
但是,我们真正需要的只是变量的别名,所以让我们指出.(同样,回到C,我们将传递我们的大数据类型的地址,解决复制问题但引入笨拙.):
void do_something(big_data& data);
big_data d;
do_something(d); // no copies at all! data aliases d within the function
Run Code Online (Sandbox Code Playgroud)
这就是为什么你会听到它说你应该一直通过引用传递东西,除非它们是原始类型.(因为内部传递别名可能是用指针完成的,就像在C中一样.对于小对象,制作副本的速度更快,然后担心指针.)
请记住,你应该是const-correct.这意味着如果您的函数没有修改参数,请将其标记为const
.如果do_something
上面只看了但没有改变data
,我们将其标记为const
:
void do_something(const big_data& data); // alias a big_data, and don't change it
Run Code Online (Sandbox Code Playgroud)
我们避免复制,我们说"嘿,我们不会修改它." 这有其他副作用(像临时变量这样的东西),但你现在不应该担心.
相反,我们的swap
功能不能const
,因为我们确实在修改别名.
希望这能澄清更多.
*粗略指针教程:
指针是保存另一个变量地址的变量.例如:
int i; // normal int
int* p; // points to an integer (is not an integer!)
p = &i; // &i means "address of i". p is pointing to i
*p = 2; // *p means "dereference p". that is, this goes to the int
// pointed to by p (i), and sets it to 2.
Run Code Online (Sandbox Code Playgroud)
所以,如果你已经看过指针版本交换函数,我们传递我们想要交换的变量的地址,然后我们进行交换,取消引用以获取和设置值.