C++:使用 & 运算符进行按引用传递

C++: using & operator for pass-by-reference

本文关键字:按引用传递 运算符 使用 C++      更新时间:2023-10-16

我正在自学c++,在这个过程中,我写了一些简单的小程序来学习基本的思想。关于"按引用传递",我很困惑为什么下面的代码可以工作(其中一些代码只是用来练习重载构造函数):

#include <iostream>
#include <string>
using namespace std;
class Dude
{
public:
  string x;
  Dude();                    // Constructor 1
  Dude(const string &a);     // Constructor 2
};
Dude::Dude() : x("hi") {}
Dude::Dude(const string &a) : x(a) {}
int main()
{
  Dude d1;
  Dude d2 = Dude("bye");
  cout << d1.x << endl;
  cout << d2.x << endl;
  return 0;
}

在"main()"中,我创建了一个类型为"Dude"的对象"d2",并使用构造函数2将"x"设置为字符串"bye"。

但是在构造函数2的声明中,我告诉它接受字符串的地址,而不是字符串本身。那么为什么我可以传递"bye"(这是一个字符串)呢?为什么我不创建一个可变字符串,然后把这个字符串的地址传递给dudud的构造函数2呢?

这实际上说明了c++最酷、最有用的特性之一:临时变量。由于您指定了字符串引用是const,编译器允许您将对该函数的临时值的引用传递给该函数。下面是Dude d2 = Dude("bye");在幕后发生的事情:

  • 编译器决定最好使用的构造函数是Dude::Dude(const string &)。如何做出这种选择是完全不同的话题。
  • 但是,为了使用该构造函数,您需要一个string值。现在,"bye"const char[4],但是编译器可以简单地将其转换为const char *,并且可以转换为string。因此,创建了一个匿名临时变量(命名为temp1)。string::string(const char *)"bye"调用,结果存储在temp1
  • Dude::Dude(const string&)调用时引用temp1。结果被赋值给d2(实际上,它被赋值给另一个临时变量),Dude的复制构造函数被调用时使用const引用,被赋值给d2。但在这种情况下,结果是相同的。)
  • temp1被丢弃。这是在temp1
  • 上运行字符串析构函数string::~string()的地方
  • 控制传递给下一条语句

我想你误解了&操作符在这种情况下的作用。获取变量的地址(&var)不同于将参数作为引用传递(就像在const string &a中那样)。

你的代码实际上在做的是隐式地创建一个新的string对象,该对象用字符串"bye"初始化,然后该对象通过引用传递给Dude构造函数。也就是说,您的代码本质上是:

Dude d2 = Dude(string("bye"));

,然后构造函数通过引用接收该字符串对象,并通过复制构造函数将其赋值给x

在这种情况下,string有一个构造函数,它接受const char*,而不是声明explicit,因此编译器将创建一个临时string(使用前面提到的构造函数string("bye")创建),然后将const string&设置为引用该临时CC_30。

两件事:

1)在你的代码中没有"地址"这样的东西。const string&表示"对string的恒定引用"。

符号&在一个完全不同的上下文中也被用作"地址"操作符来创建指针:T x; T * p = &x;,这一事实可能会让你感到困惑。但这与引用无关。

2)你实际上不一定使用你为d2声明的构造函数;相反,您使用构造函数#2创建了一个临时对象,然后通过复制构造函数从临时对象构造d2

当你用字符串参数调用第二个构造函数时,一个引用字符串副本的临时变量将被创建并传递给构造函数。

构造函数2不接受字符串的地址,const string& a表示对std::string对象的常量引用。可以向构造函数传递字符串文字的原因是,std::string类包含一个接受const char *的非显式构造函数。因此,在调用构造函数2之前,编译器会先隐式地将字符串文字转换为std::string

所以下面两行是等价的

Dude d2 = Dude("bye");
Dude d2 = Dude( std::string("bye") );

另外,在编写构造函数时,首选在初始化列表中初始化成员变量,而不是在构造函数体中初始化成员变量

Dude(const string &a) : x(a) {}

临时值可以绑定到const引用,可能就是因为这个原因。

当您调用Dude("bye")时,编译器会查看它是否与任何构造函数完全匹配(char[4])。不。然后它检查某些转换(char*)仍然没有。然后它检查用户转换,发现std::string可以从char*隐式地构造,因此它为您从char*创建std::string,并通过引用将其传递给Dude的构造函数,该构造函数会生成一个副本。在语句Dude d2 = Dude("bye");的末尾,临时字符串被自动销毁。如果我们必须为每个函数参数进行显式强制转换,那将是令人恼火的。

传递给引用形参的变量将自动传递它们的地址。这很好,因为它允许我们用值语义来处理对象。我不需要考虑给它传递一个字符串实例,我可以给它传递 "bye"

构造函数#2接受对const string的引用。这允许它接受对预先存在的对象临时对象的引用(没有const限定符,对临时对象的引用将不被接受)。

std::string有一个接受char指针的构造函数。编译器正在使用它来创建一个临时的std::string对象,然后将对该临时对象的引用传递给您的ctor。

请注意,编译器只会(隐式地)为您做一个这样的转换。如果从源数据到目标类型需要多个转换,则需要显式指定除一个转换外的所有转换。

虽然"&"是一个地址操作符,但当作为方法定义/声明的一部分声明时,它意味着将引用传递给方法。这里的参考点是d2。注意D2不是一个指针,它是一个引用。在构造函数中,"a"表示内容为"hi"的字符串对象。

这是c++中通过引用传递方法的一个典型例子。