简体   繁体   English

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

[英]C++: using & operator for pass-by-reference

I'm teaching myself C++, and in the process I'm writing simple little programs to learn basic ideas. 我正在自学C ++,在这个过程中,我正在编写简单的小程序来学习基本思想。 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". 在“main()”中,我创建一个“Dude”类型的对象“d2”,并使用构造函数2将“x”设置为字符串“bye”。

But in Constructor 2's declaration, I told it to accept an address of a string, not a string itself. 但是在构造函数2的声明中,我告诉它接受字符串的地址 ,而不是字符串本身。 So why can I pass it "bye" (which is a string). 那么为什么我可以传递它“bye”(这是一个字符串)。 Why don't I have to create a variable string, and then pass the address of that string to Constructor 2 of Dude? 为什么我不必创建变量字符串,然后将该字符串的地址传递给Dude的Constructor 2?

This actually illustrates one of the coolest and most useful features of C++: Temporary variables. 这实际上说明了C ++最酷和最有用的功能之一:临时变量。 Since you specified that the string reference is const , the compiler allows you to pass a reference to a temporary value to that function. 由于您指定了字符串引用是const ,因此编译器允许您将对临时值的引用传递给该函数。 So, here's what's happening behind the scenes with Dude d2 = Dude("bye"); 所以,这就是Dude d2 = Dude("bye");幕后发生的事情Dude d2 = Dude("bye"); :

  • The compiler determines that the best constructor to use is Dude::Dude(const string &) . 编译器确定要使用的最佳构造函数是Dude::Dude(const string &) How this choice is made is a whole different topic. 如何做出这个选择是一个完全不同的主题。
  • However, in order to use that constructor you need a string value. 但是,为了使用该构造函数,您需要一个string值。 Now, "bye" is a const char[4] , but the compiler can trivially convert that to a const char * , and that can be turned into a string . 现在, "bye"是一个const char[4]但是编译器可以平凡将其转换成一个const char *而且可以变成一个string So, an anonymous temporary variable (call it temp1 ) is created. 因此,创建了一个匿名临时变量(称为temp1 )。
  • string::string(const char *) is invoked with "bye" , and the result is stored in temp1 使用"bye"调用string::string(const char *) ,结果存储在temp1
  • Dude::Dude(const string&) is invoked with a reference to temp1 . 使用对temp1的引用调用Dude::Dude(const string&) The result is assigned to d2 (actually, it is assigned to another temporary variable and the copy constructor for Dude is invoked with a const reference to it and that is assigned to d2. But in this case the result is the same.) 结果被分配给d2 (实际上,它被分配给另一个临时变量, Dude的复制构造函数被调用,带有对它的const引用并被分配给d2。但在这种情况下,结果是相同的。)
  • temp1 is discarded. temp1被丢弃。 This is where the string destructor string::~string() is run on temp1 这是在temp1上运行字符串析构函数string::~string()
  • Control passes to the next statement 控制传递到下一个语句

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, in const string &a ). 获取变量( &var )的地址不同于表示将参数作为引用传递(就像在const 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 the Dude constructor. 你的代码实际上在做的是隐式创建一个用字符串"bye"初始化的新string对象,然后通过引用传递给Dude构造函数。 That is, your code is essentially: 也就是说,您的代码基本上是:

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

and then the constructor receives that string object by reference and assigns it to x via a copy constructor. 然后构造函数通过引用接收该字符串对象,并通过复制构造函数将其分配给x

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

Two things: 两件事情:

1) There's no such thing as an "address" in your code. 1)代码中没有“地址”这样的东西。 const string& means "constant reference to a string ". const string&表示“对string常量引用 ”。

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; 你可能会对这样一个事实感到困惑:符号&也用在完全不同的上下文中,作为创建指针的“address-of”运算符: T x; T * p = &x; 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 ; 2)你实际上并不一定要使用你声称为d2的构造函数; rather, you're creating a temporary object with your constructor #2, and then you construct d2 via the copy constructor from the temporary. 相反,您正在使用构造函数#2创建一个临时对象,然后通过临时构造函数构造d2 The direct construction reads Dude d2("bye"); 直接建筑读Dude d2("bye"); .

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

Constructor 2 is not taking an address to a string, const string& a means a constant reference to an std::string object. 构造函数2没有将地址const string& a字符串, const string& a表示对std::string对象的常量引用。 The reason why you can pass the constructor a string literal is because the std::string class contains a non-explicit constructor that takes a const char * . 您可以将构造函数传递给字符串文字的原因是因为std::string类包含一个带有const char *的非显式构造const char * So the compiler implicitly converts your string literal to an std::string first before calling Constructor 2. 因此,在调用Constructor 2之前,编译器会先隐式将您的字符串文字转换为std::string

So the following 2 lines are equivalent 所以以下两行是等价的

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

Also, when writing constructors, prefer initializing member variables in the initializer list instead of within the body of the constructor 此外,在编写构造函数时,更喜欢在初始化列表中而不是在构造函数体内初始化成员变量

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

temporaries can be bound to a const reference, probably for this reason. 由于这个原因,temporaries可以绑定到const引用。

When you call Dude("bye") , the compiler sees if that is a perfect match ( char[4] ) for any constructors. 当你调用Dude("bye") ,编译器会看到这是否是任何构造函数的完美匹配( char[4] )。 Nope. 不。 Then it checks certain conversions ( char* ) still nope. 然后它检查某些转换( char* )仍然没有。 Then it checks user conversions, and finds that std::string can be implicitly constructed from a char* So it creates a std::string from the char* for you, and passes it by reference to Dude 's constructor, which makes a copy. 然后它检查用户转换,并发现可以从char*隐式构造std::string所以它为你创建一个来自char*std::string ,并通过引用Dude的构造函数传递它,复制。 At the end of the statement Dude d2 = Dude("bye"); 在声明结尾处Dude 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" . 我不必考虑传递一个字符串的实例,我可以传递它 "bye"

Constructor #2 accepts a reference to a const string . 构造函数#2接受对const string的引用。 That allows it to accept a reference to either a pre-existing object or a temporary object (without the const qualifier, a reference to a temporary would not be accepted). 这允许它接受对预先存在的对象临时对象的引用(没有const限定符,不接受对临时对象的引用)。

std::string has a constructor that accepts a pointer to char. std::string有一个构造函数,它接受一个指向char的指针。 The compiler is using that to create a temporary std::string object, and then passing a reference to that temporary to your ctor. 编译器使用它来创建一个临时的std::string对象,然后将对该临时文件的引用传递给你的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. 如果您需要多次转换才能从源数据获取目标类型,则需要明确指定其中一个转换。

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. 在这种情况下的参考是d2。 Note that D2 is not a pointer, it is a reference. 注意,D2不是指针,它是一个引用。 In the constructor, "a" represents the string object with contents "hi". 在构造函数中,“a”表示内容为“hi”的字符串对象。 This is a typical example of a pass by reference on a method in C++. 这是C ++中方法的引用传递的典型示例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM