C++:使用 & 运算符进行按引用传递
C++: using & operator for pass-by-reference
我正在自学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 &)
。如何做出这种选择是完全不同的话题。 但是,为了使用该构造函数,您需要一个 -
Dude::Dude(const string&)
调用时引用temp1
。结果被赋值给d2
(实际上,它被赋值给另一个临时变量),Dude
的复制构造函数被调用时使用const引用,被赋值给d2。但在这种情况下,结果是相同的。) -
temp1
被丢弃。这是在temp1
上运行字符串析构函数 - 控制传递给下一条语句
string
值。现在,"bye"
是const char[4]
,但是编译器可以简单地将其转换为const char *
,并且可以转换为string
。因此,创建了一个匿名临时变量(命名为temp1
)。string::string(const char *)
被"bye"
调用,结果存储在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"的字符串对象。
- 按值传递变量与按引用传递变量具有相同的结果
- 获取 std::函数以推断按引用传递/按值传递
- C++/11 auto 关键字是在更有效时推导参数进行按引用传递,还是始终按值传递?
- 使用 enable_if 在按值传递与按引用传递之间更改函数声明
- 按引用传递和按地址传递之间的差异
- C++按引用传递还是按值传递?
- 可移动但不可复制的对象:按值传递还是按引用传递?
- 使用增量运算符按引用传递
- C++函数,按引用传递
- 按引用传递和动态内存分配之间的区别是什么
- 通过查看程序集来比较按值传递与按引用传递性能
- 在形式参数列表中自动使用 const 和按引用传递的任何明显后果
- 按引用传递函数参数
- C++按引用传递:如何使用调用堆栈
- 为什么按值传递 int 比按引用传递更快
- 是使用按引用传递来填充容器更好,还是使用返回值来填充容器更好
- 为什么 std::bind 在使用按引用传递时防止后期绑定?
- 带有按引用传递的加法运算符
- 按引用传递并使用引用运算符
- C++:使用 & 运算符进行按引用传递