Ссылки в С++

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

// структура объявления ссылок
/*тип*/ &/*имя ссылки*/ = /*имя переменной*/;

При объявлении ссылки перед её именем ставится символ амперсанда &, сама же ссылка должна быть проинициализирована именем переменной, на которую она ссылается. Тип данных, на который указывает ссылка, может быть любым, но должен совпадать с объектом, на который ссылается, то есть с типом данных ссылочной переменной. Для удобства, будем называть  переменную, на которую ссылается ссылка  «ссылочной переменной»Любое изменение значения содержащегося в ссылке повлечёт за собой изменение этого значения в переменной, на которую ссылается ссылка. Разработаем программу, в которой объявим ссылку на объект типа 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.

CppStudio.com
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.

CppStudio.com
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 не даёт изменить передаваемый аргумент внутри функции
Практика

К сожалению, для данной темы пока нет подходящих задач. Если у вас есть таковые на примете, отправте их по адресу: admin@cppstudio.com. Мы их опубликуем!

Автор: admin
Дата: 25.08.2012
Поделиться:

Комментарии

  1. npavelFax

    Заработок на дому официальное трудоустройство.

  2. JIeo

    Гы гы мне стыдно за такой коментарий

  3. JIeo

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

  4. Артур Гизатуллин

    В конце статьи рекомендуется использовать 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 в объявлении параметров функций.

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

  5. Андрей Федоров

    Почему в функции int sum_by_pointer(int *ptrvalue)   передаваемый параметр типа int когда мы передаем адрес памяти имеющюю тип char ?

    • SashaViper

      С чего Вы взяли, что передается тип «char»?
      В прототипе функции принимаемый параметр типа «int».

      int sum_by_pointer(int *);

      В самой функции то же самое:

      int sum_by_pointer(int *ptrvalue)
      {
          *ptrvalue += *ptrvalue;
          return *ptrvalue;
      }

      Ну и непосредственно в функции «main» переменная инициализирована с типом «int»:

      int value = 10;
      • Likestig

        Да, переменная value хранит значение типа int, но ведь функции sum_by_pointer параметром передается не значение переменной value, а её адрес, который имеет тип char. Ошибка? Или мы с Андреем что-то не так поняли?

    • Андрей Аршинов

      Адрес, например 00124b10 имеет тип не строка, а int(ну может больше, ну или тип «адрес»), пусть вас не пугают буквы, это шестнадцатеричная система счисления, переведём в десятичную — 1198864.

  6. Филипп Поликаренков

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

    • Zeg0

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

      • n196184611

        n196184611

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

Оставить комментарий

Вы должны войти, чтобы оставить комментарий.