Передача по ссылке на конструктор

Я решил посмотреть, сделает ли назначение ссылки для члена ссылкой. Я написал следующий фрагмент, чтобы проверить это. Там простой класс 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;
}

6 ответов

Решение

Чтобы назначить ссылку в конструкторе, вам нужно иметь элемент ссылки

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

str теперь является ссылкой на значение, которое вы передали. То же самое относится к константным ссылкам

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

Однако не забывайте, что после того, как ссылка была назначена, ее нельзя изменить, поэтому, если присвоение требует изменения str, то вместо этого он должен быть указателем.

Так как Wrapper::str это не ссылка, это независимый объект. Итак, когда вы делаете str = newStrкопируешь строку.

class Wrapper
{
public:
   string& str;

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

Обратите внимание, вы не можете принять const string& и хранить его в string&Вы бы потеряли константность в этом.

Вам нужно использовать инициализатор и объявить str как ссылка, как в:

class Wrapper {
public:
   string &str;

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

То, как вы пишете, все, что вы делаете, это копируете значение ссылки, которую вы передаете конструктору. Вы не сохраняете ссылку. Объявив ссылку в качестве члена класса и инициализировав ее ссылкой на другой экземпляр строки, вы получите искомое поведение.

Вы должны объявить Wrapper::str как string&не как string,

Ваша основная переменная тела std::string,

Ваша переменная параметра const std::string&,

Const в ссылках всегда является "низкоуровневым const", то есть он изменяет тип объекта, а не фактический объект.

Напротив, "верхний уровень const" изменяет реальный объект. Прочитайте C++ Primer на верхнем уровне const для пояснения.

Вот как выглядит ваше назначение при передаче аргументов:

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

Вы инициализируете const type reference с non-const value что приемлемо. Вы не должны менять значение std::string str используя эту ссылку. И, если вы попытаетесь изменить значение newStr внутри конструктора вы получите ошибку компиляции.

Затем вы делаете другое назначение внутри конструктора, что также приемлемо:

std::string = const std::string 

Дело в том, что wrap.str[0] не изменился str из main является то, что, хотя ссылка использовалась для создания экземпляра class str, class str имеет свой собственный объект и не связан с main str, Использование этой ссылки в параметре просто связывает этот параметр с main str; не main str в class str,

Если бы на ваши переменные класса ссылались, то это могло бы измениться.

Другие вопросы по тегам