【问题标题】:C++: difference between ampersand "&" and asterisk "*" in function/method declaration?C++:函数/方法声明中与号“&”和星号“*”之间的区别?
【发布时间】:2010-10-10 10:40:51
【问题描述】:

它们之间是否存在某种微妙的区别:

void a1(float &b) {
    b=1;
};
a1(b);

void a1(float *b) {
    (*b)=1;
};
a1(&b);

?

它们都做同样的事情(或者从 main() 看来),但第一个显然更短,但是我看到的大多数代码都使用第二种表示法。有区别吗?也许万一它是一些对象而不是浮动?

【问题讨论】:

  • 现在试着弄清楚 C++0x 中的 void a1(float &&b) 是什么意思。 :)
  • 如果它也能解释为什么 LHS & 在某些情况下可能比 * 更可取,或者如果我们有 * 作为参考,甚至根本不需要它,那就太好了。
  • @T.Webster:引用是不可变的。这意味着当您创建一个时,它肯定是指某物(因此不能为 NULL,编译器会强制您明确指定它将引用的内容),并且一旦您创建了它,它就永远不能引用其他任何东西。它们更安全,因为您不会在无意中意外地做指针算术等愚蠢的事情。
  • @Flow 我认为这个问题应该保留,因为我正在寻找这个确切的点,并且除非我访问过这个,否则不会知道一个指的是指针和一个指的是通过引用传递页。感谢您提供指向另一个问题的链接!

标签: c++ pointers reference


【解决方案1】:

两者都做同样的事情,但一个使用引用,一个使用指针。

See my answer here for a comprehensive list of all the differences

【讨论】:

  • 也赞成,而不是我的“-1”。也许有人觉得这还不够解释。感谢您的回答!
  • 很棒的帖子,已经挣扎了几个小时,在阅读了你的总结后,我得到了一个“尤里卡”时刻的祝福;)谢谢@DanielSloof!
  • 我会考虑投反对票,因为它只不过是一个链接。 SO上的答案应该完全独立,链接被用作支持/参考 - 而不是整个答案。事实上,我并没有对此投反对票,因为它指向另一个 SO 答案,这消除了我将链接发布为问题的大问题:网站可以而且确实会改变或多年来下降!但当然,如果一个答案被否决,另一个答案似乎也很可能,所以我会让它通过,根本不投票。
【解决方案2】:

是的。 * 表示法表示在堆栈上传递的是一个指针,即某物的地址。 & 表示这是一个参考。效果类似但不完全相同:

我们分两种情况:

   void examP(int* ip);
   void examR(int& i);

   int i;

如果我打电话给examP,我会写信

   examP(&i);

它获取项目的地址并将其传递到堆栈中。如果我打电话给examR

   examR(i);

我不需要它;现在编译器“以某种方式”传递了一个引用——这实际上意味着它获取并传递了i 的地址。在代码方面,那么

   void examP(int* ip){
        *ip += 1;
   }

我必须确保取消引用指针。 ip += 1 做了一些非常不同的事情。

   void examR(int& i){
        i += 1;
   }

始终更新i 的值。

要了解更多信息,请阅读“按引用调用”与“按值调用”。 & 概念通过引用提供 C++ 调用。

【讨论】:

  • 查理·马丁或了解此答案的人,请您改写/改写此答案以更简洁吗?特别是两个示例案例。我相信这里有有价值的信息,我相信这个答案和用户将从更简洁的答案中受益。我会自己编辑答案,但我不理解这两个示例。
  • 我认为您最好阅读 Stroustrup。我不怪你糊涂。
【解决方案3】:

在第一个引用示例中,您知道b 不能为NULL。以指针为例,b 可能是 NULL 指针。

但是,请注意,可以通过引用传递 NULL 对象,但这很尴尬,并且被调用的过程可以假定这样做是错误的:

a1(*(float *)NULL);

【讨论】:

    【解决方案4】:

    在第二个例子中,调用者必须在变量名前加上'&'来传递变量的地址。

    这可能是一个优势 - 调用者在他们认为自己是按值传递时,不能通过将变量作为引用传递而无意中修改变量。

    【讨论】:

      【解决方案5】:

      除了语法糖,唯一真正的区别是作为指针的函数参数可以为空。因此,如果指针版本正确处理空大小写,则可以更具表现力。 null case 也可以附加一些特殊的含义。引用版本只能对指定类型的值进行操作,而没有 null 能力。

      【讨论】:

        【解决方案6】:

        在您的示例中,两个版本的功能相同。

        第一个优点是它在调用端是透明的。想象一下它会如何寻找操作员:

        cin >> &x;
        

        以及它对于交换调用的外观如何

        swap(&a, &b);
        

        你想交换 a 和 b。而且它看起来比您第一次必须获取地址时要好得多。顺便说一句,bjarne stroustrup 写道,引用的主要原因是在调用端添加的透明度 - 特别是对于操作员。另请参阅以下是否不再明显

        &a + 10
        

        将 10 添加到 a 的内容,调用它的 operator+,或者是否将 10 添加到指向 a 的临时指针。再加上不可能只为内置操作数(如指针和整数)重载运算符。参考资料使这一点一目了然。

        如果您希望能够放置“null”,指针会很有用:

        a1(0);
        

        然后在a1中方法可以将指针与0进行比较,看指针是否指向任何对象。

        【讨论】:

        • swap(int&a, int&b) 无法确定调用是使用相同的参数进行的:swap(x, x);并早早跳出来。指针版本可以: if (a == b) return;不确定这很重要,但这是参考版本无法处理的情况。
        • 乔,它可以: if(&a == &b) return;
        【解决方案7】:

        值得注意的一大区别是外面发生了什么,你要么有:

        a1(something);
        

        或:

        a1(&something);
        

        我喜欢通过引用传递参数(总是一个 const one :))当它们没有在函数/方法中修改时(然后你也可以在里面传递自动/临时对象)并通过指针传递它们来表示和警告调用方法的代码的用户/读者可能并且可能在内部有意修改参数。

        【讨论】:

          猜你喜欢
          • 2010-12-19
          • 1970-01-01
          • 2011-09-29
          • 2023-01-14
          • 2011-09-20
          • 1970-01-01
          • 2011-02-20
          • 2022-01-08
          • 2012-04-07
          相关资源
          最近更新 更多