【问题标题】:Use of the & operator in C++ function signatures在 C++ 函数签名中使用 & 运算符
【发布时间】:2011-10-16 03:56:13
【问题描述】:

我目前正在阅读 Accelerated C++,但我意识到我并不真正了解函数签名中的 & 工作原理。

int* ptr=#

表示 ptr 现在将地址保存到 num,但这是什么意思?

void DoSomething(string& str)

据我了解,这是通过引用传递变量(这意味着传递地址)但是当我这样做时

void DoSomething(string& str)
{
  string copy=str;
}

它创建的是 str 的副本。我认为它会引发一个错误,因为我正在尝试将指针分配给一个变量。

这里发生了什么?在函数调用中使用 * 和 & 是什么意思?

【问题讨论】:

标签: c++ pass-by-reference


【解决方案1】:

引用不是指针,尽管它们的用途相似,但它们是不同的。 您可以将引用视为另一个变量的别名,即具有相同地址的第二个变量。它本身不包含地址,它只是引用与它初始化的变量相同的内存部分。

所以

string s = "Hello, wordl";
string* p = &s; // Here you get an address of s
string& r = s; // Here, r is a reference to s    

s = "Hello, world"; // corrected
assert( s == *p ); // this should be familiar to you, dereferencing a pointer
assert( s == r ); // this will always be true, they are twins, or the same thing rather

string copy1 = *p; // this is to make a copy using a pointer
string copy = r; // this is what you saw, hope now you understand it better.

【讨论】:

  • > // 这里你得到一个地址 s H.
  • @dud3 不正确,string 是一个 c++ 对象,你得到它的地址,而不是一些字符。您所指的是“数组名称”decaying 指向第一个元素的指针。但是这个代码示例中没有数组,只有 string 类型的对象是从字符串文字构造的。
  • 我明白了,问号应该放在句子的末尾。无论如何,我是 C++ 新手,我想应该在这个对象内部有一个指针,指向动态分配的字符数组中的第一个字符?
  • 如果您将 C++ 变量视为文件,则 指针 看起来像快捷方式(.lnk 文件),而 引用 看起来像硬链接。是真的吗?
【解决方案2】:

C++ 中的& 字符具有双重用途。这可能意味着(至少)

  1. 取值的地址
  2. 声明对类型的引用

您在函数签名中所指的用途是#2 的一个实例。参数string& str 是对string 实例的引用。这不仅限于函数签名,它也可以出现在方法体中。

void Example() {
  string s1 = "example";
  string& s2 = s1;  // s2 is now a reference to s1
}

我建议您查看参考资料中的 C++ 常见问题解答条目,因为它是对它们的一个很好的介绍。

【讨论】:

    【解决方案3】:

    在阅读 Accelerated C++ 的第 10 章之前,您不应该了解指针的任何事情

    引用为其他地方存在的东西创建另一个名称,别名。而已。不涉及隐藏的指针或地址。不要看窗帘后面!

    想想一个叫罗伯特的人

    guy   Robert;
    

    有时你可能想叫他鲍勃

    guy& Bob = Robert;
    

    现在 Bob 和 Robert 都指的是同一个人。你没有得到他的地址(或电话号码),只是同一件事的另一个名字。

    在你的函数中

    void DoSomething(string& str)
    {
      string copy=str;
    }
    

    它的工作原理完全相同,str 是其他地方存在的某个字符串的另一个名称。

    不要担心这是怎么发生的,只要把引用想成某个对象的名称。 编译器必须弄清楚如何连接名称,您不必这样做。

    【讨论】:

      【解决方案4】:

      在分配变量的情况下(即int* ptr = &value),使用与号将返回变量的地址(在这种情况下,地址为value)。

      在函数参数中,使用 & 符号意味着您将访问或引用传递给变量内存中的同一物理区域(如果您不使用它,则会发送一个副本)。如果您使用星号作为参数的一部分,则表示您正在传递一个变量指针,这将实现几乎相同的效果。这里的区别在于,使用 & 符号,您可以通过名称直接访问变量,但如果您传递一个指针,则必须 deference 该指针才能获取和操作实际值:

      void increase1(int &value) {
         value++;
      }
      
      void increase2(int *value) {
         (*value)++;
      } 
      
      void increase3(int value) {
         value++;
      }
      

      请注意,increase3 对您传递的原始值没有任何作用,因为只发送了一个副本:

      int main() {
         int number = 5;
         increase1(number);
         increase2(&number);
         increase3(number);
         return 0;
      }
      

      3 次函数调用结束时number 的值是 7,而不是 8。

      【讨论】:

        【解决方案5】:

        这是一个允许函数修改传递的字符串的引用,不像普通的字符串参数,修改不会影响传递给函数的字符串。

        您经常会看到 const string& 类型的参数,这是出于性能目的,因为内部引用不会创建字符串的副本。

        【讨论】:

          【解决方案6】:
          int* ptr=#
          

          第一种情况:因为 ptr 是一个内存,它存储了一个变量的地址。 & 运算符返回 num 在内存中的地址。

          void DoSomething(string& str)
          

          第二种情况:与号运算符用于表明变量是通过引用传递的,并且可以被函数更改。

          所以基本上 & 运算符根据上下文有 2 个功能。

          【讨论】:

            【解决方案7】:

            虽然通过引用传递可以由编译器通过将地址作为指针传递来实现,但在语义上它与地址或指针无关。简单来说,它只是变量的别名。

            C++ 有很多情况下,语法在具有不同语义的不同上下文中被重用,这就是其中之一。

            【讨论】:

              【解决方案8】:

              如果是:

              int* ptr=#
              

              您正在声明一个名为 ptr 的变量,其类型为 int *(int 指针),并将其值设置为“变量 num 的地址”(&num)。 “addressof”运算符 (&) 返回一个指针。

              如果是:

              void DoSomething(string& str)
              

              您将 DoSomething() 方法的第一个参数声明为“引用字符串”类型。实际上,这是定义“传递引用”的 C++ 方式。

              请注意,虽然& 运算符在这些情况下的操作类似,但它的操作方式不同。具体来说,当用作运算符时,您是在告诉编译器获取指定变量的地址;在方法签名中使用时,您是在告诉编译器该参数是一个引用。还要注意,“作为参考的参数”位与具有作为指针的参数不同。引用参数 (&) 会自动取消引用,并且永远不会接触到有关基础数据存储位置的方法;使用指针参数,您仍然通过引用传递,但是您将暴露于存储变量的方法,并且如果该方法未能执行取消引用(这种情况比您想象的更频繁),则可能会暴露问题。

              【讨论】:

                【解决方案9】:

                您正在从 str 不明确地复制构造 copy。是的,str 是一个引用,但这并不意味着您不能从中构造另一个对象。在 c++ 中,& 运算符表示三件事之一 -

                1. 当您定义普通引用变量时,您会为对象创建一个别名
                2. 当您在函数参数中使用它时,它是通过引用传递 - 您也在制作对象的别名,与副本相对应。在这种情况下,您不会注意到任何区别,因为它基本上 您传递给它的对象。当您传递的对象包含指针等时,它确实会有所不同。
                3. & 的最后一个(并且大部分与您的情况无关)含义是按位与。

                考虑引用的另一种方式(尽管有点不正确)是取消引用指针的语法糖。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-10-14
                  • 1970-01-01
                  • 2016-02-05
                  • 2014-04-12
                  • 2011-01-27
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多