我正在自学C ++,在这个过程中我正在编写简单的小程序来学习基本思想。关于“pass-by-reference”,我很困惑为什么下面的代码可以工作(一些代码只是练习重载构造函数):
#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”(这是一个字符串)。为什么我不必创建变量字符串,然后将该字符串的地址传递给Dude的构造函数2?
答案 0 :(得分:5)
这实际上说明了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
被丢弃。这是字符串析构函数string::~string()
在temp1
答案 1 :(得分:2)
我认为你误解了&
运算符在这种情况下的作用。获取变量(&var
)的地址不同于表示参数将作为引用传递(正如您在const string &a
中那样)。
您的代码实际执行的操作是隐式创建使用字符串string
初始化的新"bye"
对象,然后将该对象通过引用传递给{{> 1}}构造函数。也就是说,您的代码基本上是:
Dude
然后构造函数通过引用接收该字符串对象,并通过复制构造函数将其分配给Dude d2 = Dude(string("bye"));
。
答案 2 :(得分:2)
在这种情况下,string
有一个构造函数,它接受const char*
并且未声明explicit
,因此编译器将创建一个临时string
(使用{{创建) 1}},前面提到的构造函数)然后你的string("bye")
被设置为引用那个临时的。
答案 3 :(得分:1)
两件事:
1)代码中没有“地址”这样的东西。 const string&
表示“常量引用到string
”。
您可能会对这样一个事实感到困惑:符号&
也在完全不同的上下文中用作创建指针的“address-of”运算符:T x; T * p = &x;
。但这与参考文献无关。
2)您实际上并不一定要使用您声称为d2
的构造函数;相反,您正在使用构造函数#2创建一个临时对象,然后通过临时的复制构造函数构造d2
。直接构造为Dude d2("bye");
。
答案 4 :(得分:1)
当您使用字符串参数调用第二个构造函数时,将创建一个引用该字符串副本的临时变量并将其传递给构造函数。
答案 5 :(得分:1)
构造函数2没有将地址写入字符串,const string& a
表示对std::string
对象的常量引用。您可以将构造函数传递给字符串文字的原因是因为std::string
类包含一个带有const char *
的非显式构造函数。因此,在调用Constructor 2之前,编译器会先隐式将您的字符串文字转换为std::string
。
所以以下两行是等价的
Dude d2 = Dude("bye");
Dude d2 = Dude( std::string("bye") );
此外,在编写构造函数时,更喜欢在初始化列表中而不是在构造函数体内初始化成员变量
Dude(const string &a) : x(a) {}
答案 6 :(得分:1)
temporaries可以绑定到const引用,可能是出于这个原因。
当您调用Dude("bye")
时,编译器会查看是否与任何构造函数完全匹配(char[4]
)。不。然后它会检查某些转化(char*
)仍然不成功。然后它会检查用户转化,并发现可以std::string
隐式构建char*
,因此它会为您std::string
创建一个char*
,并通过引用传递给它Dude
的构造函数,它制作副本。在语句Dude d2 = Dude("bye");
的末尾,临时字符串将自动销毁。如果我们必须为每个函数参数自己进行显式转换,那将会很烦人。
传递给引用参数的变量将自动传递其地址。这很好,因为它允许我们处理具有值语义的对象。我不必考虑将它传递给字符串的实例,我可以传递值 "bye"
。
答案 7 :(得分:1)
构造函数#2接受对const string
的引用。这允许它接受对预先存在的对象或的临时对象的引用(没有const
限定符,不接受对临时对象的引用。)
std::string
有一个构造函数,它接受一个指向char的指针。编译器使用它来创建一个临时的std::string
对象,然后将对该临时文件的引用传递给你的ctor。
请注意,编译器只会(隐式)为您执行一个转换。如果您需要多次转换才能从源数据获取目标类型,则需要明确指定其中一个转换。
答案 8 :(得分:1)
而“&amp;”是一个addressof运算符,当作为方法定义/声明的一部分声明时,它意味着引用被传递给方法。在这种情况下的参考是d2。注意,D2不是指针,它是一个引用。在构造函数中,“a”表示内容为“hi”的字符串对象。这是C ++中方法的引用传递的典型示例。