Справочник (C ++)

редактировать

В C++ языке программирования, ссылка - это простой тип данных ссылка, который менее эффективен, но более безопасен, чем тип указателя , унаследованный от C. Название C ++ ссылка может вызвать путаницу, так как в информатике ссылка - это общий концептуальный тип данных, а указатели и ссылки C ++ являются конкретными реализациями ссылочного типа данных. Определение ссылки в C ++ таково, что она может не существовать. Его можно реализовать как новое имя для существующего объекта (аналогично ключевому слову rename в Ada).

Содержание
  • 1 Синтаксис и терминология
  • 2 Связь с указателями
  • 3 Использование ссылок
  • 4 Полиморфное поведение
  • 5 Определение ISO
  • 6 Внешние ссылки
  • 7 Ссылки
Синтаксис и терминология

Объявление формы:

, где - это тип, а - это идентификатор, тип которого ссылка на .

Примеры:

int a = 5; int r_a = a; extern int r_b;

Здесь r_aи r_bотносятся к типу "ссылка на int"

int Foo ();

Foo- это функция, которая возвращает ссылка на int"

void Bar (int r_p);

Bar- это функция со ссылочным параметром, который является "ссылкой на int"

class MyClass {int m_b; / *... * /};

MyClass- это классс членом, который ссылается на int

int FuncX () {return 42;}; int (f_func) () = FuncX;

FuncXis функция, которая возвращает (не ссылочный тип) int, а f_funcявляется псевдонимом для FuncX

const int ref = 65;

const int ref- постоянная ссылка, указывающая на часть хранилища, имеющую значение 65.

Типы, которые относятся к типу «ссылка на », иногда называются ссылкой типы . Идентификаторы ссылочного типа называются ссылочными переменными . Однако называть их переменными, как мы увидим, на самом деле неправильно.

Связь с указателями

Ссылки C ++ отличаются от указателей несколькими существенными способами:

  • Невозможно напрямую ссылаться на объект ссылки после его определения; любое вхождение его имени относится непосредственно к o bject это ссылки.
  • После того, как ссылка создана, она не может позже ссылаться на другой объект; его нельзя переустановить. Это часто делается с помощью указателей.
  • Ссылки не могут быть нулевыми, тогда как указатели могут; каждая ссылка относится к какому-либо объекту, хотя она может быть или недействительной. Обратите внимание, что по этой причине контейнеры ссылок не разрешены.
  • Ссылки не могут быть неинициализированы. Поскольку повторно инициализировать ссылку невозможно, они должны быть инициализированы сразу после создания. В частности, локальные и глобальные переменные должны быть инициализированы там, где они определены, а ссылки, которые являются членами данных экземпляров класса, должны быть инициализированы в списке инициализаторов конструктора класса. Например:
    int k; // компилятор будет жаловаться: ошибка: `k 'объявлен как ссылка, но не инициализирован

Существует простое преобразование между указателями и ссылками: оператор адресации () даст указатель, ссылающийся на тот же объект при применении к ссылке и ссылка, которая инициализируется разыменованием (*) значения указателя, будет ссылаться на тот же объект, что и этот указатель, где это возможно без вызова неопределенного поведения. Эта эквивалентность является отражением типичной реализации, которая эффективно компилирует ссылки в указатели, которые неявно разыменовываются при каждом использовании. Хотя это обычно так, стандарт C ++ не заставляет компиляторы реализовывать ссылки с помощью указателей.

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

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

  • Если он относится к объекту с автоматическим распределением, который выходит за пределы области видимости,
  • Если он относится к объекту внутри блока динамической памяти, который был освобожден.

Первое легко обнаружить автоматически, если ссылка имеет статическую область видимости, но все еще является проблемой, если ссылка является членом динамически выделяемого объекта; второй обнаружить труднее. Это единственные проблемы со ссылками, которые соответствующим образом решаются разумной политикой распределения.

Использование ссылок
  • Помимо полезной замены указателей, одно удобное применение ссылок находится в списках параметров функций, где они позволяют передавать параметры, используемые для вывода, без явного взятия адреса вызывающей стороной. Например:
void Square (int x, int out_result) {out_result = x * x; }

Затем следующий вызов поместит 9 в y:

int y; Квадрат (3, у);

Однако следующий вызов приведет к ошибке компилятора, поскольку ссылочные параметры, не уточненные с помощью const, могут быть привязаны только к адресуемым значениям:

Square (3, 6);
  • Возврат ссылки позволяет назначать вызовы функций:
    int Preinc ​​(int x) {return ++ x; // "return x ++;" было бы неправильно} Preinc ​​(y) = 5; // то же, что ++ y, y = 5
  • Во многих реализациях обычные механизмы передачи параметров часто подразумевают дорогостоящую операцию копирования для больших параметров. Ссылки, квалифицированные с помощью const, являются полезным способом передачи больших объектов между функциями, который позволяет избежать этих накладных расходов:
    void FSlow (BigObject x) {/ *... * /} void FFast (const BigObject x) {/ *... * /} BigObject y; FSlow (y); // Медленно, копирует y в параметр x. FFast (y); // Быстро, дает прямой доступ только для чтения к y.

Если FFastдействительно требует своей собственной копии x, которую он может изменять, он должен создать копию явно. Хотя тот же метод может быть применен с использованием указателей, это потребует изменения каждого сайта вызова функции, чтобы добавить к аргументу громоздкие операторы адресации (), и будет одинаково сложно отменить, если в дальнейшем объект стал меньше.

Полиморфное поведение

Продолжая взаимосвязь между ссылками и указателями (в контексте C ++), первые демонстрируют полиморфные возможности, как и следовало ожидать:

#include class A {public : A () = по умолчанию; virtual void Print () {std :: cout << "This is class A\n"; } }; class B : public A { public: B() = default; virtual void Print() { std::cout << "This is class B\n"; } }; int main() { A a; Aref_to_a = a; B b; Aref_to_b = b; ref_to_a.Print(); ref_to_b.Print(); }

Приведенный выше источник является действительным C ++ и генерирует следующий вывод:. Это класс A

Это класс B

определение ISO

Ссылки определяются стандартом ISO C ++ следующим образом (за исключением раздела примеров):

В объявлении TD, где D имеет форму

D1

и тип идентификатора в объявлении T D1 - это «список производных-деклараторов-типов T», тогда тип идентификатора D - «ссылка на список-производных-деклараторов-типов T». Ссылки с квалификацией cv имеют неправильный формат, за исключением случаев, когда cv-квалификаторы (constи volatile) вводятся посредством использования typedef (7.1.3) или аргумента типа шаблона (14.3), и в этом случае cv-квалификаторы игнорируются. [Пример: в

typedef int A; const A aref = 3; // плохо сформированный; // неконстантная ссылка, инициализированная с помощью rvalue

тип aref- это «ссылка на int», а не «constссылка на int". ] [Примечание: ссылку можно рассматривать как имя объекта. ] Объявление, указывающее тип "ссылка на cv void", неправильно сформировано.

Не указано, требует ли ссылка хранилища (3.7).

Не должно быть ссылок на ссылки, массивов ссылок и указателей на ссылки. Объявление ссылки должно содержать инициализатор (8.5.3), за исключением случаев, когда объявление содержит явный спецификатор extern(7.1.1), является объявлением члена класса (9.2) в объявлении класса или является объявление параметра или возвращаемого типа (8.3.5); см. 3.1. Ссылка должна быть инициализирована для ссылки на действительный объект или функцию. [Примечание: в частности, пустая ссылка не может существовать в четко определенной программе, потому что единственный способ создать такую ​​ссылку - это привязать ее к «объекту», полученному путем разыменования нулевого указателя, что вызывает неопределенное поведение. Как описано в 9.6, ссылку нельзя напрямую привязать к битовому полю. ]

— ISO / IEC 14882: 1998 (E), стандарт ISO C ++, в разделе 8.3.2 [dcl.ref]
Внешние ссылки
Ссылки
Последняя правка сделана 2021-06-03 11:24:37
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте