C ++: использование оператора & для передачи по ссылке - PullRequest
3 голосов
/ 03 ноября 2011

Я учу себя C ++, и в процессе я пишу простые маленькие программы для изучения основных идей. Что касается «передачи по ссылке», я запутался, почему работает следующий фрагмент кода (часть кода предназначена только для практики перегрузки конструкторов):

#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 ()" я создаю объект "d2" типа "Dude" и использую конструктор 2, чтобы установить "x" в качестве строки "пока".

Но в объявлении Конструктора 2 я сказал ему принимать адрес строки, а не саму строку. Так почему я могу передать это "пока" (это строка). Почему мне не нужно создавать переменную строку, а затем передавать адрес этой строки конструктору 2 из Dude?

Ответы [ 9 ]

5 голосов
/ 03 ноября 2011

Это фактически иллюстрирует одну из самых крутых и полезных функций 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 вызывается с константной ссылкой на него и , что назначается для d2. Но в этом Если результат одинаков.)
  • temp1 отбрасывается. Здесь деструктор строки string::~string() запускается на temp1
  • Управление переходит к следующему утверждению
2 голосов
/ 03 ноября 2011

В этом случае string имеет конструктор, который принимает const char* и не объявляется explicit, поэтому компилятор создаст временный string (созданный с помощью string("bye"), вышеупомянутый конструктор), а затем ваш const string& настроен на обращение к этому временному.

2 голосов
/ 03 ноября 2011

Я думаю, вы не понимаете, что делает оператор & в этом контексте. Взятие адреса переменной (&var) отличается от того, что означает, что параметр должен быть передан как ссылка (как у вас, в const string &a).

На самом деле ваш код неявно создает новый объект string, который инициализируется строкой "bye", а затем этот объект передается по ссылке в конструктор Dude. То есть ваш код по сути:

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

и затем конструктор получает этот строковый объект по ссылке и присваивает его x через конструктор копирования.

1 голос
/ 03 ноября 2011

Хотя «&» является оператором addressof, когда он объявлен как часть определения / объявления метода, это означает, что ссылка передается методу.Ссылка в этом случае d2.Обратите внимание, что D2 не указатель, это ссылка.В конструкторе «a» представляет строковый объект с содержимым «hi».Это типичный пример передачи по ссылке на метод в C ++.

1 голос
/ 03 ноября 2011

Конструктор # 2 принимает ссылку на const string.Это позволяет ему принимать ссылку на ранее существовавший объект или временный объект (без квалификатора const ссылка на временный объект не будет принята).

std::string имеет конструктор, который принимает указатель на символ.Компилятор использует это для создания временного std::string объекта, а затем передает ссылку на этот временный объект в ваш ctor.

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

1 голос
/ 03 ноября 2011

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

Когда вы вызываете Dude("bye"), компилятор определяет, является ли это идеальным совпадением (char[4]) для каких-либо конструкторов. Нету. Затем он проверяет определенные преобразования (char*) до сих пор нет. Затем он проверяет пользовательские преобразования и обнаруживает, что std::string может быть неявно создан из char*. Таким образом, он создает std::string из char* для вас и передает его по ссылке на конструктор Dude, который делает копию. В конце оператора Dude d2 = Dude("bye"); временная строка автоматически уничтожается. Было бы неприятно, если бы мы сами выполняли явное приведение для каждого параметра функции.

Переменные, переданные в ссылочный параметр, автоматически передадут свой адрес. Это хорошо, потому что это позволяет нам обрабатывать объекты с семантикой значения. Мне не нужно думать о передаче ему экземпляра строки, я могу передать ему значение "bye".

1 голос
/ 03 ноября 2011

Конструктор 2 не принимает адрес строки, const string& a означает постоянную ссылку на объект std::string.Причина, по которой вы можете передать конструктору строковый литерал, заключается в том, что класс std::string содержит неявный конструктор, который принимает const char *.Таким образом, компилятор неявно преобразует ваш строковый литерал в std::string, прежде чем вызывать конструктор 2.

Так что следующие 2 строки эквивалентны

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

Кроме того, при написании конструкторов предпочитайте инициализировать членпеременные в списке инициализатора, а не в теле конструктора

Dude(const string &a) : x(a) {}
1 голос
/ 03 ноября 2011

Когда вы вызываете второй конструктор со строковым аргументом, временная переменная, которая ссылается на копию строки, будет создана и передана конструктору.

1 голос
/ 03 ноября 2011

Две вещи:

1) В вашем коде нет такого понятия, как «адрес».const string& означает «константа ссылка на string».

Возможно, вас смущает тот факт, что символ & также используется в совершенно ином контексте какОператор address-of для создания указателя: T x; T * p = &x;.Но это не имеет ничего общего со ссылками.

2) На самом деле вы не обязательно используете конструктор, для которого вы заявляете d2;скорее вы создаете временный объект с помощью вашего конструктора # 2, а затем вы создаете d2 через конструктор копирования из временного.Прямая конструкция гласит Dude d2("bye");.

...