Как вернуть ссылку на объект c
Перейти к содержимому

Как вернуть ссылку на объект c

  • автор:

Возврат из функции объекта по ссылке

Теперь в main() создаю массив объектов типа Stock и присваиваю указателю top значение одного из элементов массива:

for (int st = 1; st < STKS; st++) < top = &top ->TopVal(stocks[st]); > 

Объясните, почему при присваивании указателю top значения из функции TopVal следует указывать знак ссылки, ведь из функции уже передается ссылка?

Отслеживать
44.8k 3 3 золотых знака 39 39 серебряных знаков 90 90 бронзовых знаков
задан 16 дек 2016 в 13:53
Misha Gorshenin Misha Gorshenin
3 2 2 бронзовых знака

3 ответа 3

Сортировка: Сброс на вариант по умолчанию

В этом предложении

используется оператор взятия адреса & . В C++ многие символы перегружены и имеют несколько значений в зависимости от контекста. Так, например, символ * может означать бинарный оператор умножения, оператором разыменования указателя и использоваться в объявлениях для объявления указателя.

В свою очередь символ & может означать оператор взятия адреса, как в приведенной вами программе, ссылку при объявлении ссылок, а также бинарный битовый оператор AND.

Итак, в данном объявлении функции- члена класса

const Stock & Stock::TopVal(const Stock & _st) const ^^^ ^^^ < if (_st.total_val >total_val) return _st; else return *this; > 

символ & используется для объявления ссылок. Функция возвращает ссылку на объект типа const Stock , а также объявляет в качестве параметра ссылку на объект такого эе типа const Stock .

А в этом предложении

указателю top , который скорей всего объявлен как

const Stock *top; 

присваивается адрес того объекта, ссылка на который возвращается из функции.

Чтобы было более понятно, то рассмотрите следующий пример

int x = 10; int &r = x; int *p = &x; r = 20; *p = 30; 

В этом примере объявляется ссылка r на объект x и указатель p , который будет содержать адрес объекта x . Ссылку можно рассматривать как альтернативное имя объекта — как алиас объекта. То еть к области памяти, где расположен объект x , вы можете обращаться по исходному имени x , или используя имя r .

Отслеживать
ответ дан 16 дек 2016 в 13:59
Vlad from Moscow Vlad from Moscow
44.8k 3 3 золотых знака 39 39 серебряных знаков 90 90 бронзовых знаков

Из функции передается ссылка, но ссылка — это как бы псевдоним, а не адрес. Т.е. если у вас есть

int x; int& r = x; int* p = &x; 

то r — обратите внимание, инициализируется x , а не адресом, как указатель. Как именно внутренне реализована ссылка — в данном случае не играет роли.

Вы используете r вместо x — например, в присваивании r = 5; . B точно так же вы получаете адрес через ссылку — p = &x тождественно p = &r; .

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

Отслеживать
ответ дан 16 дек 2016 в 14:26
220k 15 15 золотых знаков 120 120 серебряных знаков 231 231 бронзовый знак

В книге Стенли Б. Липпман, Жози Лажойе, Барбара Э. Му. Язык программирования C++. Базовый курс. Пятое издание. 2017 в главе 15 рассматривается иерархия классов Quote — Disc_quote — Bulk_quote.

У меня возникла необходимость передать в некоторую функцию ссылки объекты базового или производных классов и вернуть из этой функции также ссылки на эти объекты.

Приведенный на этой странице пример не срабатывает:

auto ref_return(Quote& ref_obj) < return ref_obj; >; // . Bulk_quote bulk_quote; auto b_q = ref_return(bulk_quote); // Возвращает не ссылку, а объект. // У меня выстрелили вот такие конструкции: // Определение фунции, которая должна возвратить обычную ссылку: auto ref_return(Quote& ref_obj) -> Quote& < return ref_obj; >; // Вызов должен быть таким: decltype(auto) any_obj_ref = ref_return(bulk_quote); // Такая же проблема была и с лямбда, и примерно так же она решилась: // Механизм возврата простой ссылки из лямда-функции: // Лямбда выражение должно быть таким: auto ret_derived = [](Quote& any_quote_obj) -> Quote& ; Quote any_quote_obj - объект базового класса // Вызов должен быть таким: decltype(auto) bulk_quote_obj = ret_derived(bulk_quote); 

Может быть, кому-нибудь окажется полезной эта информация.

Возврат ссылок

Функция может возвращать ссылку. В результате такая функция может использоваться в левой части оператора присваивания. В качестве примера рассмотрим следующую простую программу:

#include
char &replace(int i) ; // возврат ссылки
char s [80] = «Hello There»;
int main()
replace(5) = ‘X’; // присвоение X пробелу после Hello
cout return 0;
>
char &replace(int i)
return s [ i ];
>

Эта программа заменяет пробел между словами «Hello» и «There» символом «X». В результате программа выводит на экран «HelloXThere».

Функция replace() в соответствии со своим объявлением возвращает ссылку на символьный мас­сив. В соответствии со своей реализацией функция replace() возвращает ссылку на элемент масси­ва s, определяющийся аргументом i. Далее возвращаемая функцией replace() ссылка используется функцией main() для присвоения элементу буквы «X».

Передача ссылок на объекты

Когда объект передается функции как аргумент, создается копия объекта. Более того, при создании этой копии конструктор объекта не вызывается. Вместо этого делается точная копия объекта. Однако по окончании выполнения функции вызывается деструк­тор копии объекта. Если по каким-либо причинам нежелательно, чтобы создавалась копия объекта или чтобы вызывался деструктор, то надо передать объект в функцию по ссылке. При передаче по ссылке копия объекта не создается. Это также означает, что объект-параметр не будет уничто­жаться при выходе из функции и соответственно не будет вызван деструктор. В качестве примера запустим следующую программу:

Программа выдает следующие результаты:

Constructing 1
-10
Destructing 1

Как можно видеть, деструктор объекта cl вызывался только один раз.

При передаче объекта в функцию по ссылке действие над объектом внутри функции модифи­цирует этот объект. И эти изменения сохраняют силу после завершения работы функции.

Как вернуть ссылку на объект c

При возвращении указателя из функции он должен содержать либо значение nullptr , либо адрес, который все еще действителен. Поэтому не следует возвращать из функции адрес автоматической локальной переменной, так как она удаляется после завершения этой функции. Так, рассмотрим следующий некорректный пример функции, которая возвращает большее число из двух:

// пример некорректного возвращения значения int* max(int a, int b) < if (a >b) return &a; else return &b; >

Параметры функции аналогичны переменным — при вызове функции в стеке для них выделяется память. И вданном случае возвращается адрес участка памяти соответствующего параметра ( return &a или return &b ). Но после возвращения адреса функция завершает свою работу, соответствующие участки памяти очищаются, параметры удаляются, поэтому возвращенный адрес будет недействительным. И хотя компилятор даже может скомпилировать данную функцию, ограничившись предупреждениями, но такая функция не будет работать корректно.

Тем не менее это не значит, что мы в принципе не можем возвращать указатель из функции. Например, возьмем следующую ситуацию:

#include int* max(int*, int*); int main() < int n; int m; int* ptr = max(&n, &m); std::cout // пример корректного возвращения значения int* max(int *a, int *b) < if (*a >*b) // разыменовываем указатели return a; else return b; >

Здесь аналогичная функция, которая вычисляет наибольшее из двух чисел, только передаются не сами числа, а адреса переменных. Поэтому возвращенный адрес по прежнему будет действительным.

При этом нам необязательно присваивать результат переменной или константе, можно напрямую обратиться к результату функции:

int main() < int n; int m; std::cout 

Возвращение ссылки

Функция также может возвращать ссылку. Однако тут мы можем столкнуться с теми же проблемами, что и при возвращении указателей: не следует возвращать ссылку на локальный объект, который создается внутри функции. Поскольку все создаваемые в функции объекты удаляются после ее завершения, а их память очищается, то возвращаемая ссыла будет указывать на несуществующий объект, как в следующем случае:

// пример некорректного возвращения ссылки int& max(int a, int b) < if (a >b) return a; else return b; >

Здесь функция возвращает ссылку на максимальное значение - один из переданных параметров. Но поскольку память, выделенная для параметров, передаваемых по значению, после выполнения функции очищается, то возвращенная ссылка в итоге будет указывать на несуществующий объект.

Чтобы выйти из ситуации, мы можем передавать значения по ссылке:

#include int& max(int&, int&); int main() < int n; int m; int result = max(n, m); std::cout // пример корректного возвращения ссылки int& max(int& a, int& b) < if (a >b) return a; else return b; >

Стоит отметить, что если параметры представляют константные ссылки, то чтобы возвратить одну из этих ссылок, функция должна возвращать константную ссылку.

#include const int& max(const int&, const int&); int main() < int n; int m; int result = max(n, m); std::cout // пример корректного возвращения ссылки const int& max(const int& a, const int& b) < if (a >b) return a; else return b; >

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *