C++:使用 &引用传递运算符
我正在自学 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()”中,我创建了一个对象“d2”类型为“Dude”,并使用构造函数 2 将“x”设置为字符串“bye”。
但在构造函数 2 的声明中,我告诉它接受字符串的地址,而不是字符串本身。那么为什么我可以传递它“再见”(这是一个字符串)。为什么我不必创建一个变量字符串,然后将该字符串的地址传递给 Dude 的构造函数 2?
I'm teaching myself C++, and in the process I'm writing simple little programs to learn basic ideas. With respect to "pass-by-reference", I'm confused why the following piece of code works (some of the code is just there to practice overloading constructors):
#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;
}
In "main()", I create an object "d2" of type "Dude", and use Constructor 2 to set "x" to be the string "bye".
But in Constructor 2's declaration, I told it to accept an address of a string, not a string itself. So why can I pass it "bye" (which is a string). Why don't I have to create a variable string, and then pass the address of that string to Constructor 2 of Dude?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
这实际上说明了 C++ 最酷、最有用的功能之一:临时变量。由于您指定字符串引用为 const,编译器允许您将对临时值的引用传递给该函数。因此,以下是
Dude d2 = Dude("bye");
幕后发生的事情:Dude::Dude(const string &)
。如何做出这个选择是一个完全不同的话题。string
值。现在,"bye"
是一个const char[4]
,但编译器可以轻松地将其转换为const char *
,并且 that 可以转换成字符串
。因此,创建了一个匿名临时变量(称之为temp1
)。string::string(const char *)
通过"bye"
调用,结果存储在temp1
Dude:: Dude(const string&)
是通过对temp1
的引用来调用的。结果被分配给d2
(实际上,它被分配给另一个临时变量,并且使用对它的 const 引用调用Dude
的复制构造函数,并且 < /em> 被分配给 d2。但在这种情况下,结果是相同的。)temp1
被丢弃。这是字符串析构函数string::~string()
在temp1
上运行的地方This actually illustrates one of the coolest and most useful features of C++: Temporary variables. Since you specified that the string reference is
const
, the compiler allows you to pass a reference to a temporary value to that function. So, here's what's happening behind the scenes withDude d2 = Dude("bye");
:Dude::Dude(const string &)
. How this choice is made is a whole different topic.string
value. Now,"bye"
is aconst char[4]
, but the compiler can trivially convert that to aconst char *
, and that can be turned into astring
. So, an anonymous temporary variable (call ittemp1
) is created.string::string(const char *)
is invoked with"bye"
, and the result is stored intemp1
Dude::Dude(const string&)
is invoked with a reference totemp1
. The result is assigned tod2
(actually, it is assigned to another temporary variable and the copy constructor forDude
is invoked with a const reference to it and that is assigned to d2. But in this case the result is the same.)temp1
is discarded. This is where the string destructorstring::~string()
is run ontemp1
我认为您误解了
&
运算符在这种情况下的作用。获取变量的地址 (&var
) 与表示参数将作为引用传递(正如您所见,在const string 中) &a
)。您的代码实际上所做的是隐式创建一个新的
string
对象,该对象使用字符串"bye"
进行初始化,然后该对象通过引用传递 到Dude
构造函数。也就是说,您的代码本质上是:然后构造函数通过引用接收该字符串对象,并通过复制构造函数将其分配给
x
。I think you're misunderstanding what the
&
operator does in this context. Taking the address of a variable (&var
) is different from signifying that a parameter is to be passed as a reference (as you have, inconst string &a
).What your code is actually doing is implicitly creating a new
string
object that's initialized with the string"bye"
, and then that object is passed by reference to theDude
constructor. That is, your code is essentially:and then the constructor receives that string object by reference and assigns it to
x
via a copy constructor.在本例中,
string
有一个构造函数,该构造函数采用const char*
并且未声明显式
,因此编译器将创建一个临时>string
(使用上述构造函数string("bye")
创建),然后将您的const string&
设置为引用该临时值。In this case,
string
has a constructor which takes aconst char*
and is not declaredexplicit
, so the compiler will create a temporarystring
(created withstring("bye")
, the aforementioned constructor) and then yourconst string&
is set to refer to that temporary.有两件事:
1)代码中没有“地址”之类的东西。
const string&
表示“对字符串
的常量引用”。您可能会感到困惑,因为符号
&
还在完全不同的上下文中用作创建指针的“address-of”运算符:T x; T * p = &x;
。但这与参考文献无关。2) 您实际上不一定使用您为
d2
声明的构造函数;相反,您使用构造函数 #2 创建一个临时对象,然后通过临时对象的复制构造函数构造d2
。直接构造为Dude d2("bye");
。Two things:
1) There's no such thing as an "address" in your code.
const string&
means "constant reference to astring
".You're possibly confused by the fact that the symbol
&
is also used in an entirely different context as the "address-of" operator to create a pointer:T x; T * p = &x;
. But that has nothing to do with references.2) You're not actually necessarily using the constructor that you claim for
d2
; rather, you're creating a temporary object with your constructor #2, and then you constructd2
via the copy constructor from the temporary. The direct construction readsDude d2("bye");
.当您使用字符串参数调用第二个构造函数时,将创建一个引用字符串副本的临时变量并将其传递给构造函数。
When you call second constructor with a string argument, a temporary variable which references a copy of the string will be created and passed to the constructor.
构造函数 2 没有获取字符串的地址,
const string& a
表示对std::string
对象的常量引用。您可以向构造函数传递字符串文字的原因是因为std::string
类包含一个采用const char *
的非显式构造函数。因此,在调用构造函数 2 之前,编译器首先将字符串文字隐式转换为std::string
。因此,以下 2 行是等效的。
此外,在编写构造函数时,更喜欢在初始值设定项列表中初始化成员变量,而不是在构造函数体内
Constructor 2 is not taking an address to a string,
const string& a
means a constant reference to anstd::string
object. The reason why you can pass the constructor a string literal is because thestd::string
class contains a non-explicit constructor that takes aconst char *
. So the compiler implicitly converts your string literal to anstd::string
first before calling Constructor 2.So the following 2 lines are equivalent
Also, when writing constructors, prefer initializing member variables in the initializer list instead of within the body of the constructor
可能出于这个原因,临时变量可以绑定到 const 引用。
当您调用
Dude("bye")
时,编译器会查看这是否与任何构造函数完美匹配 (char[4]
)。没有。然后它检查某些转换(char*
)仍然没有。然后它检查用户转换,发现std::string
可以从char*
隐式构造,因此它创建了一个std::string
从char*
中为您获取,并通过引用将其传递给Dude
的构造函数,该构造函数会生成一个副本。在语句Dude d2 = Dude("bye");
结束时,临时字符串将自动销毁。如果我们必须自己对每个函数参数进行显式转换,那会很烦人。传递给引用参数的变量将自动传递它们的地址。这很好,因为它允许我们用值语义来处理对象。我不必考虑向它传递一个字符串实例,我可以向它传递值
“bye”
。temporaries can be bound to a const reference, probably for this reason.
When you call
Dude("bye")
, the compiler sees if that is a perfect match (char[4]
) for any constructors. Nope. Then it checks certain conversions (char*
) still nope. Then it checks user conversions, and finds thatstd::string
can be implicitly constructed from achar*
So it creates astd::string
from thechar*
for you, and passes it by reference toDude
's constructor, which makes a copy. At the end of the statementDude d2 = Dude("bye");
the temporary string is automatically destroyed. It would be irritating if we had to do the explicit casts ourselves for every single function parameter.Variables passed to a reference parameter will automatically pass their address instead. This is nice, because it allows us to treat objects with value semantics. I don't have to think about passing it an instance of a string, I can pass it the value
"bye"
.构造函数 #2 接受对
const string
的引用。这允许它接受对预先存在的对象或临时对象的引用(如果没有 const 限定符,则不会接受对临时对象的引用)。std::string
有一个接受 char 指针的构造函数。编译器使用它来创建一个临时std::string
对象,然后将该临时对象的引用传递给您的构造函数。请注意,编译器只会(隐式)为您执行一次这样的转换。如果您需要多次转换才能从源数据转换为目标类型,则需要显式指定除其中一种转换之外的所有转换。
Constructor #2 accepts a reference to a
const string
. That allows it to accept a reference to either a pre-existing object or a temporary object (without theconst
qualifier, a reference to a temporary would not be accepted).std::string
has a constructor that accepts a pointer to char. The compiler is using that to create a temporarystd::string
object, and then passing a reference to that temporary to your ctor.Note that the compiler will only (implicitly) do one conversion like this for you. If you need more than one conversion to get from the source data to the target type, you'll need to specify all but one of those conversions explicitly.
而“&”是一个addressof运算符,当作为方法定义/声明的一部分声明时,意味着引用被传递给该方法。本例中的参考是 d2。请注意,D2 不是指针,而是引用。在构造函数中,“a”代表内容为“hi”的字符串对象。这是 C++ 中方法的引用传递的典型示例。
While "&" is an addressof operator, when declared in as part of method definition/declaration, it means that the reference is passed to the method. The reference in this case is d2. Note that D2 is not a pointer, it is a reference. In the constructor, "a" represents the string object with contents "hi". This is a typical example of a pass by reference on a method in C++.