Передача по ссылке на конструктор
Я решил посмотреть, будет ли назначение ссылки члену, сделав элемент ссылкой. Я написал следующий фрагмент, чтобы проверить его. Там есть простой класс Wrapper
с std::string
как переменная-член. Я беру a const string&
в конструкторе и назначаю его переменной public member. Позже в методе 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;
}
Ответы
Ответ 1
Чтобы назначить ссылку в конструкторе, вам нужно иметь ссылочный элемент
class A{
std::string& str;
public:
A(std::string& str_)
: str(str_) {}
};
str теперь ссылается на значение, которое вы передали. То же самое относится к const refs
class A{
const std::string& str;
public:
A(const std::string& str_)
: str(str_) {}
};
Однако не забывайте, что после того, как ссылка была назначена, она не может быть изменена, поэтому, если для назначения требуется изменение str, тогда вместо этого она должна быть указателем.
Ответ 2
class Wrapper
{
public:
string& str;
Wrapper(string& newStr) : str(newStr) {}
};
Обратите внимание: вы не можете принять const string&
и сохранить его в string&
, вы потеряете const-correctness при этом.
Ответ 3
Поскольку Wrapper::str
не является ссылкой, это независимый объект. Поэтому, когда вы делаете str = newStr
, вы копируете строку.
Ответ 4
Вам нужно использовать инициализатор и объявить str
в качестве ссылки, как в:
class Wrapper {
public:
string &str;
Wrapper(string& newStr)
: str(newStr) {
}
};
Как вы его пишете, все, что вы делаете, это копирование значения ссылки, которую вы передаете в constuctor. Вы не сохраняете ссылку. Объявив ссылку как член класса и инициализируя ее ссылкой на другой экземпляр строки, вы получите поведение, которое вы ищете.
Ответ 5
Вы должны объявить Wrapper::str
как string&
, а не как string
.
Ответ 6
Переменная основного тела std::string.
Вы переменная параметра const std::string &.
Константа в ссылках всегда "низкий уровень const"
Это означает, что он изменяет тип объекта, а не фактический объект. Напротив, "верхний уровень const" изменяет фактический объект. Прочитайте С++ Primer на верхнем уровне const для уточнения.
Вот как выглядит ваше задание при передаче аргументов.
const std::string & = std:: str;//Значения оммиты. i.e const std::string netStr = std::string str
Вы инициализируете ссылку на const-тип с неконстантным значением, которое является приемлемым. Вы не должны изменять значение std::string str, используя эту ссылку. Попробуйте изменить значение конструктора newStr внутри. Вы получите ошибку компиляции
Затем вы выполните другое задание.
std::string= const std::string внутри конструктора, который также является приемлемым.
Тот факт, что wrap.str [0] не изменил str main, заключается в том, что, хотя ссылка была использована для создания экземпляра класса str, класс str имеет свой собственный объект и не связан с главной str. Использование ссылки в параметре просто связывает этот параметр с главной str не main str с классом str. Если ваша переменная класса была ссылкой, она могла бы быть изменена.