通过引用传递给构造函数

46

我决定测试将引用分配给成员是否会使成员成为引用。我编写了以下片段进行测试。有一个简单的类Wrapper,其中包含一个std::string作为成员变量。在构造函数中获取一个const string&并将其赋值给公共成员变量。稍后在main()方法中修改成员变量,但我传递给构造函数的string保持不变,为什么?我认为在Java中,变量会发生更改,为什么这个代码片段没有呢?在这种情况下引用是如何工作的呢?

#include <iostream>
#include <string>
using namespace std;

class Wrapper
{
public:
   string str;

   Wrapper(const string& newStr)
   {
      str = newStr;
   }
};

int main (int argc, char * const argv[]) 
{
   string str = "hello";
   cout << str << endl;
   Wrapper wrapper(str);
   wrapper.str[0] = 'j'; // should change 'hello' to 'jello'
   cout << str << endl;
}

4
在C++中,类型由您决定,它们不会神奇地变成其他类型。如果您使用“string”,就会得到一个“string”。如果您想要一个引用,您应该使用“string &”。 - Kerrek SB
2
你用太简单的问题来折磨人了 :) - Mikhail
2
在Java中,变量不会改变,因为代码甚至无法编译;在Java中,字符串是不允许被修改的。 - Rob Kennedy
6个回答

50

要在构造函数中分配引用,你需要有一个引用成员。

 class A{
     std::string& str;
 public:
     A(std::string& str_)
     :    str(str_) {} 
 };

现在,str是对您传递的值的引用。const引用也适用相同规则。

 class A{
     const std::string& str;
 public:
     A(const std::string& str_)
     :    str(str_) {} 
 };

但是不要忘记,一旦分配了引用,它就不能被更改。如果分配需要更改str,则必须使用指针。


1
有趣的是,将引用作为数据成员是应该避免的:https://herbsutter.com/2020/02/23/references-simply/ - Markon

13

因为Wrapper::str不是一个引用,而是一个独立的对象。所以当你执行str = newStr时,你正在复制这个字符串。


6
class Wrapper
{
public:
   string& str;

   Wrapper(string& newStr) : str(newStr) {}
};

请注意,您不能接受const string&并将其存储在string&中,这样做会失去常量正确性。


5
您需要使用初始化器,将str声明为引用,如下所示:
class Wrapper {
public:
   string &str;

   Wrapper(string& newStr)
      : str(newStr) {
   }
};

你当前的写法只是复制了传入构造函数的引用的值。你没有保存这个引用。通过将一个引用声明为类成员,并使用指向另一个字符串实例的引用进行初始化,你可以得到你想要的行为。


1
你的代码试图用一个指向常量的引用来初始化一个指向可变对象的引用。 - Luc Touraille
固定的...这就是我盲目地从原帖中复制的结果。 - andand

1

您的主体变量是std::string

您的参数变量是const std::string&

引用中的const始终是“低级const”,这意味着它修改对象的类型而不是实际对象。

相比之下,“顶层const”修改了实际对象。请阅读C++ Primer on Top level const以进行澄清。

以下是传递参数时分配的方式:

const std::string& = std::str; //Values are ommited
// i.e const std::string newStr = std::string str

您正在使用非常量值初始化const类型引用,这是可以接受的。您不应该使用该引用更改std::string str的值。如果您尝试在构造函数中更改newStr的值,则会出现编译错误。
接下来,您在构造函数中执行另一个赋值操作,这也是可以接受的:
std::string = const std::string 
wrap.str[0]没有改变mainstr是因为,虽然使用引用来实例化class str,但class str有自己的对象,不与main str链接。在参数中使用该引用只将该参数链接到main str,而不是将main str链接到class str

如果引用了类变量,则可能已更改。


1
你应该将 Wrapper::str 声明为 string&,而不是 string

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接