Справочник (C ++) - Reference (C++)
Эта статья нужны дополнительные цитаты для проверка.Ноябрь 2013) (Узнайте, как и когда удалить этот шаблон сообщения) ( |
в C ++ язык программирования, а ссылка это простой ссылка тип данных, который менее мощный, но более безопасный, чем тип указатель тип унаследованный от C. Название Справочник по C ++ может вызвать путаницу, поскольку в информатике ссылка - это общий концептуальный тип данных, указатели и Ссылки на C ++ являются конкретными реализациями ссылочного типа данных. Определение ссылки в C ++ таково, что она не должна существовать. Его можно реализовать как новое имя для существующего объекта (аналогично ключевому слову rename в Ada).
Синтаксис и терминология
Объявление формы:
<Type>& <Name>
куда <Type>
это тип и <Name>
является идентификатор чей тип ссылка на <Type>
.
Примеры:
int а = 5;int& r_a = а;внешний int& r_b;
Здесь, r_a
и r_b
относятся к типу "ссылка на int
"
int& Фу();
Фу
это функция, которая возвращает "ссылку на int
"
пустота Бар(int& r_p);
Бар
- это функция со ссылочным параметром, который является "ссылкой на int
"
учебный класс Мой класс { int& m_b; /* ... */ };
Мой класс
это учебный класс
с членом, который ссылается на int
int FuncX() { возвращаться 42 ; };int (&f_func)() = FuncX;
FuncX
это функция, которая возвращает (не ссылочный тип) int
и f_func
является псевдоним за FuncX
const int& ссылка = 65;
const int & ref
постоянная ссылка, указывающая на часть хранилища, имеющую значение 65.
Типы, которые являются своего рода "ссылкой на <Type>
"иногда называют ссылочные типы. Идентификаторы ссылочного типа называются ссылочные переменные. Позвонить им Переменнаяоднако, как мы увидим, на самом деле это неправильное название.
Связь с указателями
Ссылки C ++ отличаются от указателей несколькими существенными способами:
- Невозможно напрямую ссылаться на объект ссылки после того, как он определен; любое вхождение его имени относится непосредственно к объекту, на который он ссылается.
- После того, как ссылка создана, ее нельзя впоследствии использовать для ссылки на другой объект; Не может быть пересаженный. Часто это делается с помощью указателей.
- Ссылки не могут быть ноль, тогда как указатели могут; каждая ссылка относится к какому-либо объекту, хотя она может быть или недействительной. Обратите внимание, что по этой причине контейнеры ссылок не разрешены.
- Ссылки не могут быть неинициализированными. Поскольку повторно инициализировать ссылку невозможно, они должны быть инициализированы сразу после создания. В частности, локальные и глобальные переменные должны быть инициализированы там, где они определены, а ссылки, которые являются членами данных экземпляров класса, должны быть инициализированы в списке инициализаторов конструктора класса. Например:
int& k; // компилятор пожалуется: ошибка: `k 'объявлен как ссылка, но не инициализирован
Существует простое преобразование между указателями и ссылками: оператор адресации (&
) даст указатель, ссылающийся на один и тот же объект при применении к ссылке, и ссылку, которая инициализируется из разыменования (*
) значения указателя будет ссылаться на тот же объект, что и этот указатель, где это возможно без вызова неопределенного поведения. Эта эквивалентность является отражением типичной реализации, которая эффективно компилирует ссылки в указатели, которые неявно разыменовываются при каждом использовании. Хотя это обычно так, стандарт C ++ не заставляет компиляторы реализовывать ссылки с помощью указателей.
Следствием этого является то, что во многих реализациях работа с переменной с автоматическим или статическим временем жизни через ссылку, хотя синтаксически аналогична прямому доступу к ней, может включать скрытые операции разыменования, которые являются дорогостоящими.
Кроме того, поскольку операции со ссылками настолько ограничены, их гораздо легче понять, чем указатели, и они более устойчивы к ошибкам. Хотя указатели можно сделать недействительными с помощью различных механизмов, от переноса нулевого значения до арифметики за пределы границ и недопустимых приведений до их создания из произвольных целых чисел, ранее действительная ссылка становится недействительной только в двух случаях:
- Если он относится к объекту с автоматическим выделением, который выходит за рамки,
- Если он относится к объекту внутри блока динамической памяти, который был освобожден.
Первый легко обнаружить автоматически, если ссылка имеет статическую область видимости, но все же проблема, если ссылка является членом динамически выделяемого объекта; второй обнаружить сложнее. Это единственные проблемы со ссылками, которые соответствующим образом решаются разумной политикой распределения.
Использование ссылок
- Помимо полезной замены указателей, одно удобное применение ссылок - это списки параметров функций, где они позволяют передавать параметры, используемые для вывода, без явного взятия адреса вызывающей стороной. Например:
пустота Квадрат(int Икс, int& out_result) { out_result = Икс * Икс;}
Тогда следующий вызов поместит 9 в у:
int у;Квадрат(3, у);
Однако следующий вызов приведет к ошибке компилятора, поскольку ссылочные параметры не определены с const
может быть привязан только к адресуемым значениям:
Квадрат(3, 6);
- Возврат ссылки позволяет назначать вызовы функций:
int& Preinc(int& Икс) { возвращаться ++Икс; // "return x ++;" было бы неправильно}Preinc(у) = 5; // то же, что ++ y, y = 5
- Во многих реализациях обычные механизмы передачи параметров часто подразумевают дорогостоящую операцию копирования для больших параметров. Ссылки квалифицированы с
const
- полезный способ передачи больших объектов между функциями, позволяющий избежать этих накладных расходов:пустота FSlow(BigObject Икс) { /* ... */ } пустота FFast(const BigObject& Икс) { /* ... */ }BigObject у;FSlow(у); // Медленно, копирует y в параметр x.FFast(у); // Быстро, дает прямой доступ только для чтения к y.
Если FFast
на самом деле требуется собственная копия Икс что он может изменять, он должен явно создавать копию. Хотя тот же метод может быть применен с использованием указателей, это потребует изменения каждого сайта вызова функции, чтобы добавить громоздкий адрес-of (&
) к аргументу, и было бы так же сложно отменить, если бы объект впоследствии стал меньше.
Полиморфное поведение
Продолжая взаимосвязь между ссылками и указателями (в контексте C ++), первые демонстрируют полиморфные возможности, как и следовало ожидать:
#включают <iostream>учебный класс А { общественный: А() = дефолт; виртуальный пустота Распечатать() { стандартное::cout << "Это класс А п"; }};учебный класс B : общественный А { общественный: B() = дефолт; виртуальный пустота Распечатать() { стандартное::cout << "Это класс B п"; }};int главный() { А а; А& ref_to_a = а; B б; А& ref_to_b = б; ref_to_a.Распечатать(); ref_to_b.Распечатать();}
Приведенный выше источник является действительным C ++ и генерирует следующий вывод: Это класс А
Это класс B
Определение ISO
Ссылки определены стандартом ISO C ++ следующим образом (за исключением раздела примеров):
В объявлении T D, где D имеет вид
& D1а тип идентификатора в объявлении T D1 - "производный-декларатор-тип-список
Т
, "тогда тип идентификатора D -"производный-декларатор-тип-список ссылка наТ
. "Ссылки с квалификацией cv имеют неправильный формат, кроме случаев, когда квалификаторы cv (const
и летучий) вводятся с помощьюtypedef
(7.1.3) или аргумента типа шаблона (14.3), и в этом случае cv-квалификаторы игнорируются. [Пример: вtypedef int& А;const А ареф = 3; // плохо сформированный;// неконстантная ссылка, инициализированная с помощью rvalueтип
ареф
"ссылка наint
", нет "const
ссылка наint
". ] [Примечание: ссылку можно рассматривать как имя объекта. ] Декларатор, указывающий тип "ссылка на резюме void "неправильно сформирован.Не указано, требует ли ссылка хранилища (3.7).
Не должно быть ссылок на ссылки, массивов ссылок и указателей на ссылки. Объявление ссылки должно содержать инициализатор (8.5.3) кроме случаев, когда объявление содержит явное
внешний
спецификатор (7.1.1), является объявлением члена класса (9.2) в объявлении класса или является объявлением параметра или возвращаемого типа (8.3.5); см. 3.1. Ссылка должна быть инициализирована для ссылки на действительный объект или функцию. [Примечание: в частности, пустая ссылка не может существовать в четко определенной программе, потому что единственный способ создать такую ссылку - это привязать ее к «объекту», полученному разыменованием нулевого указателя, что вызывает неопределенное поведение. Как описано в 9.6, ссылку нельзя напрямую привязать к битовому полю. ]— ISO / IEC 14882: 1998 (E), стандарт ISO C ++, в разделе 8.3.2 [dcl.ref]