C++ 如何在C++;?

C++ 如何在C++;?,c++,reference-parameters,C++,Reference Parameters,我试图理解如何使用参考参数。在我的文本中有几个例子,但是它们太复杂了,我无法理解为什么以及如何使用它们 您希望如何以及为什么使用参考资料?如果您没有将参数设置为引用,而是关闭了&,会发生什么情况 例如,这些函数之间的区别是什么: int doSomething(int& a, int& b); int doSomething(int a, int b); 我知道引用变量用于更改形式->引用,从而允许参数的双向交换。然而,这是我的知识范围,一个更具体的例子会有很大帮助 将引用视为

我试图理解如何使用参考参数。在我的文本中有几个例子,但是它们太复杂了,我无法理解为什么以及如何使用它们

您希望如何以及为什么使用参考资料?如果您没有将参数设置为引用,而是关闭了
&
,会发生什么情况

例如,这些函数之间的区别是什么:

int doSomething(int& a, int& b);
int doSomething(int a, int b);
我知道引用变量用于更改形式->引用,从而允许参数的双向交换。然而,这是我的知识范围,一个更具体的例子会有很大帮助

将引用视为。当您在引用上调用某个对象时,实际上是在引用所引用的对象上调用它

int i;
int& j = i; // j is an alias to i

j = 5; // same as i = 5
说到功能,请考虑:

void foo(int i)
{
    i = 5;
}
上面,
inti
是一个值,传递的参数是按值传递的。这意味着如果我们说:

int x = 2;
foo(x);
i
将是
x
的副本。因此,将
i
设置为5对
x
没有影响,因为它是正在更改的
x
的副本。但是,如果我们将
i
作为参考:

void foo(int& i) // i is an alias for a variable
{
    i = 5;
}
然后说
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
好的,很好。我们想让它成为一个函数,因为:
swap(x,y)更容易阅读。那么,让我们试试这个:

void swap(int x, int y)
{
    int temp = x;
    x = y;
    y = temp;
}
这行不通!问题是这是交换两个变量的副本。即:

int a, b;
swap(a, b); // hm, x and y are copies of a and b...a and b remain unchanged
在C语言中,当引用不存在时,解决方案是传递这些变量的地址;也就是说,使用指针*:

void swap(int* x, int* y)
{
    int temp = *x;
    *x = *y;
    *y = temp;
}

int a, b;
swap(&a, &b);
这很有效。然而,它的使用有点笨拙,实际上有点不安全<代码>交换(nullptr,nullptr)
,交换两个Nothing并取消对空指针的引用…未定义的行为!可通过一些检查进行修复:

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;
}
但看起来我们的代码有多笨拙。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
既易于使用,又安全。(我们不能意外地传入null,因为没有null引用。)这是有效的,因为在函数内部发生的交换实际上是在函数外部别名的变量上发生的

(请注意,切勿编写
交换
函数。:)标头
中已存在一个交换函数,并且它已模板化,可用于任何类型。)


另一个用途是删除调用函数时发生的副本。考虑一下我们有一个非常大的数据类型。复制此对象需要很多时间,我们希望避免:

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 :<
这就是为什么你会听到它说你应该一直通过引用传递东西,除非它们是基本类型。(因为内部传递别名可能是通过指针完成的,就像在C中一样。对于小对象,创建副本比担心指针更快。)

记住你应该是正确的。这意味着如果函数不修改参数,请将其标记为
const
。如果上面的
做某事
只是查看数据,而没有更改数据,我们会将其标记为
常量

void do_something(const big_data& data); // alias a big_data, and don't change it
我们避免复制,我们说“嘿,我们不会修改这个。”这还有其他副作用(比如临时变量),但现在你不应该担心

相反,我们的
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.

因此,如果您看到了指针版本交换函数,我们将传递要交换的变量的地址,然后进行交换,取消引用以获取和设置值。

让我们以一个名为
increment
的函数为例,该函数增加其参数。考虑:

void increment(int input) {
 input++;
}
在实际参数上传递给函数的参数副本上发生更改时,它将不起作用。所以

int i = 1;
std::cout<<i<<" ";
increment(i);
std::cout<<i<<" ";
函数中对
输入所做的更改实际上是对实际参数所做的更改。这将产生a和b的可变引用中传递的
12

//的预期输出。
// Passes in mutable references of a and b.
int doSomething(int& a, int& b) {
  a = 5;
  cout << "1: " << a << b;  // prints 1: 5,6
}

a = 0;
b = 6;
doSomething(a, b);
cout << "2: " << a << ", " << b;  // prints 2: 5,6
内部剂量测量(内部和a、内部和b){ a=5;
我不知道这是否是最基本的,但这是

typedef int Element;
typedef std::list<Element> ElementList;

// Defined elsewhere.
bool CanReadElement(void);
Element ReadSingleElement(void); 

int ReadElementsIntoList(int count, ElementList& elems)
{
    int elemsRead = 0;
    while(elemsRead < count && CanReadElement())
        elems.push_back(ReadSingleElement());
    return count;
}
typedef int元素;
类型定义标准::列表元素列表;
//在别处定义。
bool-CanReadElement(void);
元素ReadSingleElement(void);
int ReadElementsIntoList(int计数、元素列表和元素)
{
int elemsRead=0;
while(elemsRead
这里我们使用一个引用将元素列表传递到
ReadElementsIntoList()中
。通过这种方式,函数将元素直接加载到列表中。如果不使用引用,则
elems
将是传入列表的副本,该列表将添加元素,但当函数返回时,
elems
将被丢弃

这是双向的。在
count
的情况下,我们不将其作为引用,因为我们不想修改传入的计数,而是返回读取的元素数。这允许调用代码将实际读取的元素数与请求的数目进行比较;如果它们不匹配,则
可以读取
// Passes in mutable references of a and b.
int doSomething(int& a, int& b) {
  a = 5;
  cout << "1: " << a << b;  // prints 1: 5,6
}

a = 0;
b = 6;
doSomething(a, b);
cout << "2: " << a << ", " << b;  // prints 2: 5,6
// Passes in copied values of a and b.
int doSomething(int a, int b) {
  a = 5;
  cout << "1: " << a << b;  // prints 1: 5,6
}

a = 0;
b = 6;
doSomething(a, b);
cout << "2: " << a << ", " << b;  // prints 2: 0,6
// Passes in const references a and b.
int doSomething(const int &a, const int &b) {
  a = 5;  // COMPILE ERROR, cannot assign to const reference.
  cout << "1: " << b;  // prints 1: 6
}

a = 0;
b = 6;
doSomething(a, b);
typedef int Element;
typedef std::list<Element> ElementList;

// Defined elsewhere.
bool CanReadElement(void);
Element ReadSingleElement(void); 

int ReadElementsIntoList(int count, ElementList& elems)
{
    int elemsRead = 0;
    while(elemsRead < count && CanReadElement())
        elems.push_back(ReadSingleElement());
    return count;
}
using namespace std;

void foo(int y){
    y=2;
}

int main(){
    int x=1;
    foo(x);
    cout<<x;//outputs 1
}
using namespace std;

void foo(int & y){
    y=2;
}

int main(){
    int x=1;
    foo(x);
    cout<<x;//outputs 2
}
// changes to a & b hold when the function exits
void swap(int& a, int& b) {
    int tmp = a;
    a = b;
    b = tmp;
}

// changes to a & b are local to swap_noref and will go away when the function exits
void swap_noref(int a, int b) {
    int tmp = a;
    a = b;
    b = tmp;
}

// changes swap_ptr makes to the variables pointed to by pa & pb
// are visible outside swap_ptr, but changes to pa and pb won't be visible
void swap_ptr(int *pa, int *pb) {
    int tmp = *pa;
    *pa = *pb;
    *pb = tmp;
}

int main() {
    int x = 17;
    int y = 42;
    // next line will print "x: 17; y: 42"
    std::cout << "x: " << x << "; y: " << y << std::endl

    // swap can alter x & y
    swap(x,y);
    // next line will print "x: 42; y: 17"
    std::cout << "x: " << x << "; y: " << y << std::endl

    // swap_noref can't alter x or y
    swap_noref(x,y);
    // next line will print "x: 42; y: 17"
    std::cout << "x: " << x << "; y: " << y << std::endl

    // swap_ptr can alter x & y
    swap_ptr(&x,&y);
    // next line will print "x: 17; y: 42"
    std::cout << "x: " << x << "; y: " << y << std::endl
}
int a = 17;
             ____
a @ 0x1000: | 17 |
             ----
int *pa = &a;
              ______                     ____
pa @ 0x10A0: |0x1000| ------> @ 0x1000: | 17 |
              ------                     ----