В программировании на С++ очень часто используются ссылки.
Самый логичный вопрос, который обязан возникнуть у начинающих:
"Что такое ссылка?"
В общем случае можно найти приблизительно следующее определение: "Ссылка — это альтернативное имя, это псевдоним объекта" и прочие определения, в которых говорится, что ссылка — это другое имя объекта.
Для создания ссылки используют знак &, применяемый к типу.
C++
1
int& x;
Хотя можно встретить различные варианты написания:
C++
1
2
3
int& x;
int& x;
int&x
Во всех случаях знак амперсанда связан с типом, приписанном левее. Пробелы ни на что не влияют.
Типы, к которым привязан знак амперсанда, называют ссылочными типами:
C++
1
2
int&//Ссылочный int
float&//Ссылочный float
Создание переменной ссылочного типа — это не создание переменной, а создание нового идентификатора под какой-то объект, чаще всего уже именованный.
Создаётся ссылка так же, как создаются самые обычные переменные, объявляется тип, обозначается, что тип ссылочный, после чего даётся имя, как будто бы сделали переменную и назвали её заданным именем.
C++
1
int& x;//Создание ссылки "x"
Но в отличие от обычных переменных ссылки требуют немедленной инициализации себя объектом.
C++
1
2
3
//Полноценное создание ссылки
intvalue;//объект, существующий до создания ссылки
int& x = value;//Создание ссылки "x" и инициализация её объектом value
Рассмотрим листинг с полноценным созданием ссылки. Ссылка по природе своей является переиначиванием уже существующих имён переменных на свой лад. Из-за того что в обычных условиях нельзя просто взять и обозначить знаком равенства имена переменных, было решено использовать специальный тип: ссылку на тип.
C++
1
2
int*ptr;//Указатель на int
int&ref_value;//Ссылка на int
Чтение справа-налево поспособствует правильному пониманию объявляемых сущностей. ptr — это указатель на int; аналогично: ref-value — это ссылка на int.
И вот этот специальный тип помогает наслаивать на уже существующее имя дополнительные названия. А чтобы можно было знать, что за имя дополняется новыми для себя названиями, в ссылку нужно немедленно записать главного виновника торжества, т. е. обозначить, к чему нужно привязать созданную ссылку.
Создание ссылки предполагает наличие объекта в памяти, чтобы или позаимствовать имя у такого объекта, или создать альтернативное имя неименованному объекту:
C++
1
2
3
4
5
6
7
intmain(){
int& a = *(new int);//Создание ссылки на неименованный участок памяти
//Теперь "a" можно использовать как будто это переменная "a"
a=10;
cout<<a;
deletea;
}
Создаётся ссылка точно также, как создаются обычные переменные. Но обязательным условием является оперативное взятие имени объекта. Т. е. ссылку необходимо инициализировать сразу же.
Чтобы ссылка могла существовать, обязательно должен быть объект, ради которого она живёт или рождается.
C++
1
2
3
4
5
6
7
8
9
10
11
12
//Borland C++ 3.1 Объявление ссылки Листинг #1
#include <conio.h>
#include <iostream.h>
intmain()
{
clrscr();
intx;//x - это обычная переменная. При этом x есть объект типа int
int&a = x;//объявляем ссылку а. a ссылается на x (любая обработка a это обработка x)
cin.get();
}
Тут видно, что объявляется переменная x, а после этого объявленная x присваивается в переменную, у которой слева стоит знак &.
Если справа от названия типа стоит знак амперсанда, то имеем дело с ссылками.
Любые имена переменных — это всего-лишь идентификаторы участков памяти. Создание ссылки — это добавление нового идентификатора на уже используемый чем-то адрес памяти.
Смотрим листинг #1. Когда была создана переменная x, программа подобрала ей некоторый участок памяти. После этого была создана ссылка a и узами брака связала свою жизнь с созданной ранее переменной x.
За всё время своей жизни ссылка связана только с одним объектом. Переназначить объект ссылке нельзя.
Знак амперсанда, обозначающий создание ссылки, относится к типу, указываемому для переменной. Пробелы ни на что не влияют:
C++
1
2
3
4
5
6
inta=100;
int& ref1 = a;//& относится к int
int&ref2 = a;//& относится к int
int& ref3 = a;//& относится к int
//и ref1, и ref2, и ref3 - это a
Знак &, относящийся к типу, — это ссылка. В противном случае это или взятие адреса, или битовое "И", или что-либо ещё.
В общем, если вы видите рядом с амперсандом название типа, то, значит, сиё ссылка. Ссылку объявляют и сразу привязывают к существующему объекту.
Вот только после освоения и осознания вами приведённой мной для вас информации, в пору говорить:
Ссылка — это псевдоним настоящему имени объекта.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//Borland C++ 3.1 Ссылки - это псевдонимы настоящим именам переменным Листинг #2
#include <conio.h>
#include <iostream.h>
intmain()
{
clrscr();
intx=100;//Объект, именованный "x"
int&a = x;//Создание псевдонима "a" для "x"
cout<<"a = "<<a<<endl;//Вывели значение a (a=объект из адреса x (a=х), x=100 => a=100)
cout<<"x = "<<x<<endl;// Вывели значение x (x=100)
cout<<"&a = "<<&a << endl;//Вывели адрес a
cout<<"&x = "<<&x << endl;//Вывели адрес x
//Адреса a и x одинаковые //На самом деле выводится только адрес "x", ибо это основной объект.
//"a" - это "x"
/*Изменением значение ссылки меняется только объект, на который она ссылается*/
x=888;//Изменили только переменную x
cout<<"a = "<<a<<endl;//Вывели значение a (a=объект из адреса x (a=х), x=888=>a=888)
cout<<"x = "<<x<<endl;// Вывели значение x (x=888)
//Адреса а и x вы легко выведите самостоятельно и можете убедиться, что они не изменились.
}
В листинге #2 показывается, почему говорят, что ссылка — это ещё одно имя названию переменной. Вот есть некоторая обязательная переменная x, на имя которой ссылается ссылка a. Меняете x, поменяется и выводимое значение ссылки, ссылающейся на имя x.
В момент объявления ссылки a переменная x уже существует в природе, и ссылка a привязывается к этому объекту: теперь независимо от выбранного имени (x или a) работа будет происходить с переменной x.
Этот эффект получается, потому что переменная-ссылка a, ссылаясь на имя переменной x, как будто бы обращается к тому значению, которое в эту x записано.
Многих начинающих волнует вопрос отличия ссылки от указателя.
Самое главное отличие ссылки от указательной переменной в том, что ссылка не является объектом. Для названия ссылки может не отводиться место в памяти. Для указательной переменной место в памяти выделяется всегда.
Остальные отличия касаются использования ссылок в коде.
Ссылка не может ссылаться на несуществующий объект, указатель может. (Можно сделать, чтобы ссылка ссылалась на несуществующий объект, но в таком случае поведение программы непредсказуемо)
Ссылку нельзя переназначить, а указательную переменную можно.
В необходимости одномоментной инициализации вы легко убедитесь, если оставите только голое объявление ссылочного имени:
C++
1
int&x;//Нельзя. Ссылочное название должно быть инициализировано объектом.
В невозможности переиначивания ссылки вы убедитесь, если попробуете использовать ссылку для связи с именем объекта после инициализации ссылки:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//Borland C++ 3.1 Переназначить ссылку нельзя Листинг #3
#include <conio.h>
#include <iostream.h>
intmain()
{
clrscr();
intx,y;
int&a = x;//"a" есть ссылка на "x", следовательно "a" это другое имя для переменной "x"
x=100;cout<<a<<endl;//a = x = 100;
y=999;//Присвоили в переменную "y" некоторое значение
a=y;// Попытка задать новое имя переменной "y" приводит к обычному присвоению в "x" значения "y"
cout<<x;//x = 999
}
Ссылка не является переменной, но для удобства читателя я буду использовать термин ссылка-переменная. В листинге #3 было изменено значение переменной, к которой ссылка привязана, и это отобразилось на результате вывода ссылки-переменной на экран.
После вывода на экран происходит вероятная попытка связать ссылку-переменную с новой переменной, попытка подменить ссылку, но вместо того, чтобы привязаться к новой переменной, ссылка-переменная записывает значение в привязанную уже однажды к себе переменную. Для незнающего человека такое поведение программы может оказаться немного неожиданным: вместо переназначения имени была произведена обычная операция присвоения.
Хотели: a = адрес "y"
Получили: x = значение "y"
В общем, смысл в том, что указателем можно тыкать в разные адреса, а ссылкой можно тыкнуть в имя, и тыкнуть только единожды (при инициализации) — в другие имена уже не ткнуть, не получится.
Подводя итоги, акцентирую внимание на самом важном:
Ссылка — это синоним имени переменной, т. е. другое имя для использования переменной.
Ссылка не является переменной. Она просто буквенное обозначение для связи с каким-то единственным объектом.
Ссылка обязательно или ссылается на имя уже существующего значения, или ссылается на неназванное имя (пример был приведён выше).
На самом деле можно сделать так, чтобы ссылка ссылалась на несуществующее значение, но присутствие такой ссылки в программе делает поведение программы непредсказуемым.
Ссылка обязательно должна быть инициализирована.
Ссылка ссылается на имя объекта, но работа с названием ссылки — это работа с объектом, привязанном к ссылке.
При объявлении переменных ссылка создаётся с помощью знака амперсанд, пишемого правее названия типа.
Нельзя поменять связь ссылки {имя ссылки — имя объекта}, которая задаётся при создании ссылки.
Обращение к ссылке происходит так же, как обращение к обычной переменной.
Всякое изменение путём использования ссылки влияет не на ссылку, а на объект, к которому однажды была привязана ссылка.
Тип ссылки должен совпадать с типом объекта, к которому ссылка привязывается. Есть два исключения (при полиморфизме, при неявных приведениях тип не обязан совпадать точно)
Изменение объекта как будто бы влияет на ссылку, это иллюзия, т. к. ссылка — это идентификатор этого самого объекта.
На один объект можно задать сколь угодно ссылок. Все они будут только-лишь псевдонимами настоящему имени объекта.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//Borland C++ 3.1 Ссылки Листинг #4
#include <conio.h>
#include <iostream.h>
intmain()
{
clrscr();
inta;
int&x = a;//Всё равно, что объявили вторую a, только назвали x
a=100;//Поменяли сам объект
cout<<a<<" = "<<x<<endl;//При таком обращении идет обращение к a
x=777;//Ссылка ленивая сволочь, всю работу сваливает на объект. Происходит что-то вроде транзита. "Ссылка умыла руки" и вышло не (x=777), а (a=777)
cout<<a<<" = "<<x<<endl;//обращаемся к объекту. (a=a=777). Задача ссылки только свалить всю работу на плечи объекта, на который она по просьбе программиста ссылается
cin.get();
}
Широкое применение ссылки получили в использовании их в параметрах функций. При работе с большими объектами данных они, ссылки, оказались полезными удобствами, помогающими во многих случаях избегать работы с указательными переменными.
14 комментариев на «“Ссылки в C++ для начинающих. Поверхностное знакомство”»
Настя, адрес переменной «а» в оперативной памяти, вы бы для начала почитали, что такое программа и как она работает, ну и про ОЗУ тоже почитайте, а потом уже про ссылки и указатели на с/с++
Спасибо вам больше за то, что вы делаете и КАК объясняете. Я, в принципе, все понимаю из «классических» учебников, но как доходит дело до кода, нюансов и разложения по полочкам, то тут и всплывает типичный теоретик, не способный что-то правильно делать окромя того, что было разобрано в учебниках.
Вы же просто магически все преподносите, лучшей конкретизации и многоступенчатого объяснения и не придумаешь.
А что будет есть сделать так
Спасибо, всё очень просто и доходчиво 🙂
Спасибо, без воды объяснили.
Каждый понял своё. Часто неправильно.
я нихрена не поняла словечки какие то не понятные что такое сумбур? что за переменная?
я вообще далёкая но очень хочу научиться и везде вот эти непонятные слова , хоть словарь заводи
что за память какая память где она находиться зачем ёмаё
я уже 5 раз читаю и врубиться не могу
только не думайте что я тормоз , я просто хочу знать всё очень очень подробно
что за адрес переменной «а»
Настя, адрес переменной «а» в оперативной памяти, вы бы для начала почитали, что такое программа и как она работает, ну и про ОЗУ тоже почитайте, а потом уже про ссылки и указатели на с/с++
Спасибо вам больше за то, что вы делаете и КАК объясняете. Я, в принципе, все понимаю из «классических» учебников, но как доходит дело до кода, нюансов и разложения по полочкам, то тут и всплывает типичный теоретик, не способный что-то правильно делать окромя того, что было разобрано в учебниках.
Вы же просто магически все преподносите, лучшей конкретизации и многоступенчатого объяснения и не придумаешь.
Вот честно — ОЧЕНЬ круто!
Я одного не понял — нафиг она нужна эта ссылка, если она всего лишь дублирует имя основной переменной?
да. Нафиг?