Ссылки – особый тип данных, являющийся скрытой формой указателя, который при использовании автоматически разименовывается. Ссылка может быть объявлена как другим именем, так и как псевдоним переменной, на которую ссылается.
// структура объявления ссылок /*тип*/ &/*имя ссылки*/ = /*имя переменной*/;
При объявлении ссылки перед её именем ставится символ амперсанда &
, сама же ссылка должна быть проинициализирована именем переменной, на которую она ссылается. Тип данных, на который указывает ссылка, может быть любым, но должен совпадать с объектом, на который ссылается, то есть с типом данных ссылочной переменной. Для удобства, будем называть переменную, на которую ссылается ссылка «ссылочной переменной». Любое изменение значения содержащегося в ссылке повлечёт за собой изменение этого значения в переменной, на которую ссылается ссылка. Разработаем программу, в которой объявим ссылку на объект типа int
.
// №1.cpp: определяет точку входа для консольного приложения. #include "stdafx.h" #include <iostream> using namespace std; int main(int argc, char* argv[]) { int value = 15; int &reference = value; // объявление и инициализация ссылки значением переменной value cout << "value = " << value << endl; cout << "reference = " << reference << endl; reference+=15; // изменяем значение переменной value посредством изменения значения в ссылке cout << "value = " << value << endl; // смотрим, что получилось, как будет видно дальше значение поменялось как в ссылке, cout << "reference = " << reference << endl; // так и в ссылочной переменной system("pause"); return 0; }
// код Code::Blocks
// код Dev-C++
// №1.cpp: определяет точку входа для консольного приложения. #include <iostream> using namespace std; int main(int argc, char* argv[]) { int value = 15; int &reference = value; // объявление и инициализация ссылки значением переменной value cout << "value = " << value << endl; cout << "reference = " << reference << endl; reference+=15; // изменяем значение переменной value посредством изменения значения в ссылке cout << "value = " << value << endl; // смотрим, что получилось, как будет видно дальше значение поменялось как в ссылке, cout << "reference = " << reference << endl; // так и в ссылочной переменной return 0; }
В строке 10 объявлена ссылка reference
типа int
на переменную value
. В строке 13 суммируется значение переменной value
с числом 15, через ссылку reference
. Результат работы программы смотреть на рисунке 1.
value = 15 reference = 15 value = 30 reference = 30 Для продолжения нажмите любую клавишу . . .
Рисунок 1 — Ссылки в С++
Просмотрев результат работы программы можно сказать, что через ссылку меняется значение ссылочной переменной. Таким образом, сама ссылка не имеет как таковой копии значения взятой у переменной при инициализации ссылки, а всего лишь ссылка ссылается на ссылочную переменную посредством её адреса.
Ссылки, как правило, в большинстве случаев используют в функциях как ссылки-параметры или ссылки-аргументы. Напомню, что в языке программирования С++ в функции передаются данные по значению и по ссылке. Так вот, когда происходит передача по значению, те данные, которые необходимо передать, нужно сначала скопировать, а когда передаётся большой объём данных, то только на передачу затрачивается большое количество времени и ресурсов. В таком случае необходимо использовать передачу по ссылке, в этом случае данные копировать нет необходимости, так как к ним обеспечен прямой доступ, но нарушают безопасность данных, хранимых в ссылочных переменных, так как открывают прямой доступ к этим данным. Хотя далее мы рассмотрим, как обеспечить целостность данных и скорость их передачи. Для этого, разработаем программу, в которой создадим три функции, аргументы в которых будут передаваться по значению и по ссылке. Вдобавок ко всему этому ещё и передачу через указатель осуществим. Частенько возникает путаница между указателями и ссылками, на первый взгляд и ссылки и указатели работают одинаково, но разница все, же есть и весьма значительная.
// reference.cpp: определяет точку входа для консольного приложения. #include "stdafx.h" #include <iostream> using namespace std; int sum_by_value(int );// суммирование по значению int sum_by_reference(int &);// суммирование по ссылке int sum_by_pointer(int *); // суммирование по указателю int _tmain(int argc, _TCHAR* argv[]) { int value = 10; cout << "sum_by_value = " << sum_by_value(value) << endl; cout << "value = " << value << endl; // значение переменной осталось неизменным cout << "sum_by_reference = " << sum_by_reference(value) << endl; cout << "value = " << value << endl; // значение переменной изменилось cout << "sum_by_pointer = " << sum_by_pointer(&value) << endl; cout << "value = " << value << endl; // значение переменной изменилось ещё раз system("pause"); return 0; } int sum_by_value(int value)// функция принимающая аргумент по значению { value += value; return value; } int sum_by_reference(int &reference) // функция принимающая аргумент по ссылке { reference += reference; return reference; } int sum_by_pointer(int *ptrvalue)// функция принимающая аргумент через указатель { *ptrvalue += *ptrvalue;// арифметика с указателем return *ptrvalue; }
// код Code::Blocks
// код Dev-C++
// reference.cpp: определяет точку входа для консольного приложения. #include <iostream> using namespace std; int sum_by_value(int );// суммирование по значению int sum_by_reference(int &);// суммирование по ссылке int sum_by_pointer(int *); // суммирование по указателю int main() { int value = 10; cout << "sum_by_value = " << sum_by_value(value) << endl; cout << "value = " << value << endl; // значение переменной осталось неизменным cout << "sum_by_reference = " << sum_by_reference(value) << endl; cout << "value = " << value << endl; // значение переменной изменилось cout << "sum_by_pointer = " << sum_by_pointer(&value) << endl; cout << "value = " << value << endl; // значение переменной изменилось ещё раз return 0; } int sum_by_value(int value)// функция принимающая аргумент по значению { value += value; return value; } int sum_by_reference(int &reference) // функция принимающая аргумент по ссылке { reference += reference; return reference; } int sum_by_pointer(int *ptrvalue)// функция принимающая аргумент через указатель { *ptrvalue += *ptrvalue;// арифметика с указателем return *ptrvalue; }
Начальное значение осталось неизменным в случае передачи по значению, тогда как передача по ссылке и через указатель изменили значение передаваемой переменной. Таким образом, нет необходимости использовать глобальные переменные при необходимости изменения значения передаваемой переменной, нужно воспользоваться ссылкой или указателем. В случае использования указателя строка 18 нельзя забывать про операцию взятия адреса, так как аргументом является указатель. В случае со ссылкой, достаточно указать только имя переменной и всё строка 16. Результат работы программы показан на рисунке 2.
sum_by_value = 20 value = 10 sum_by_reference = 20 value = 20 sum_by_pointer = 40 value = 40 Для продолжения нажмите любую клавишу . . .
Рисунок 2 — Ссылки в С++
В чём же разница между указателями и ссылками? Основное назначение указателя – это организация динамических объектов, то есть размер, которых может меняться (увеличиваться или уменьшаться). Тогда как ссылки предназначены для организации прямого доступа к тому, или иному объекту. Главное отличие состоит во внутреннем механизме работы. Указатели ссылаются на участок в памяти, используя его адрес. А ссылки ссылаются на объект, по его имени (тоже своего рода адрес). Если нет необходимости изменить передаваемое значение в ссылочной переменной, но нужно выиграть в скорости, используйте спецификатор const
в объявлении параметров функций. Только так и можно защитить данные от случайного их изменения или полной потере.
int sum_by_reference(const int &reference) // функция принимающая аргумент по ссылке // квалификатор const не даёт изменить передаваемый аргумент внутри функции
Комментарии
npavelFax
Заработок на дому официальное трудоустройство.
JIeo
Гы гы мне стыдно за такой коментарий
JIeo
В последний програме добавить поеснения что результат первой функции является локальным и уничтожается,а вызовы с сылками и указателями сохраняется я вот не очень опытный но это прерасно знаю,но на первый взгляд показалась что сылка ничего неделает,лиш разобравшись все стало понятно
Артур Гизатуллин
В конце статьи рекомендуется использовать const для защиты от изменения переменной. Но у меня MVS пищет ошибку:
Ошибка 1 error C3892: reference: невозможно присваивать значения переменной, которая объявлена как константа c:\users\дом\documents\visual studio 2013\projects\consoleapplication3\исходный код.cpp 28 1 ConsoleApplication3
2 IntelliSense: выражение должно быть допустимым для изменения левосторонним значением c:\Users\Дом\Documents\Visual Studio 2013\Projects\ConsoleApplication3\Исходный код.cpp 28 2 ConsoleApplication3
В чем причина?
Stanisław Pietkiewicz
Всё верно. Ведь const для того и нужен, чтобы вы случайно не изменили переменную.
Андрей Федоров
Почему в функции
int
sum_by_pointer(
int
*ptrvalue) передаваемый параметр типа int когда мы передаем адрес памяти имеющюю тип char ?
SashaViper
С чего Вы взяли, что передается тип «char»?
В прототипе функции принимаемый параметр типа «int».
В самой функции то же самое:
Ну и непосредственно в функции «main» переменная инициализирована с типом «int»:
Likestig
Да, переменная value хранит значение типа int, но ведь функции sum_by_pointer параметром передается не значение переменной value, а её адрес, который имеет тип char. Ошибка? Или мы с Андреем что-то не так поняли?
Андрей Аршинов
Адрес, например 00124b10 имеет тип не строка, а int(ну может больше, ну или тип «адрес»), пусть вас не пугают буквы, это шестнадцатеричная система счисления, переведём в десятичную — 1198864.
Филипп Поликаренков
мне кажется, что было бы уместнее разместить эту тему в разделе «Функции, локальные и глобальные переменные, рекурсия», так как функция, приводимая тут как пример, еще не пройдена, если идти по порядку.
Zeg0
Согласен с тобой. Я вообще эту тему пропустил. Позже выучу, знакомый программист сказал что это редко или вообще не используется
n196184611
Знакомый программист не совсем по-моему прав здесь, есть смысл в том чтобы изменять значение переменных внутри функций — можно довольно использовать часто.