Лекции.ИНФО


А вот самая интересная строка в программе.



f() = 99.1; // Изменяем значение val.

При выполнении этой инструкции присваивания значение переменной val становится равным числу 99,1. И вот почему: поскольку функция f() возвращает ссылку на переменную val, эта ссылка и является приемником инструкции присваивания. Таким образом, значение 99,1 присваивается переменной val косвенно, через ссылку на нее, которую возвращает функция f().

Наконец, при выполнении строки

cout << f() << ''; // Отображаем новое значение val.

отображается новое значение переменной val (после того, как ссылка на переменную val будет возвращена в результате вызова функции f() в инструкции cout).

Приведем еще один пример программы, в которой в качестве значения, возвращаемого функцией, используется ссылка (или значение ссылочного типа).

#include <iostream>

using namespace std;

double &change_it(int i);

// Функция возвращает ссылку.

double vals[] = {1.1, 2.2, 3.3, 4.4, 5.5};

Int main()

{

 int i;

 cout << "Вот исходные значения: ";

 for(i=0; i<5; i++)

  cout << vals[i] << ' ';

 cout << '';

 change_it(1) = 5298.23; // Изменяем 2-й элемент.

 change_it(3) = -98.8; // Изменяем 4-й элемент.

 cout << "Вот измененные значения: ";

 for(i=0; i<5; i++)

  cout << vals[i] << ' ';

 cout << '';

 return 0;

}

double &change_it(int i)

{

 return vals[i]; // Возвращаем ссылку на i-й элемент.

}

Эта программа изменяет значения второго и четвертого элементов массива vals. Результаты ее выполнения таковы.

Вот исходные значения: 1.1 2.2 3.3 4.4 5.5

Вот измененные значения: 1.1 5298.23 3.3 -98.8 5.5

Давайте разберемся, как они были получены. Функция change_it() объявлена как возвращающая ссылку на значение типа double. Говоря более конкретно, она возвращает ссылку на элемент массива vals, который задан ей в качестве параметра i. Таким образом, при выполнении следующей инструкции функции main()

change_it(1) = 5298.23; // Изменяем 2-й элемент.

функция change_it() возвращает ссылку на элемент vals[1]. Через эту ссылку элементу vals[1] теперь присваивается значение 5298,23. Аналогичные события происходят при выполнении и этой инструкции.

change_it(3) = -98.8; // Изменяем 4-й элемент.

Поскольку функция change_it() возвращает ссылку на конкретный элемент массива vals, ее можно использовать в левой части инструкции для присвоения нового значения соответствующему элементу массива.

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

// Здесь ошибка: нельзя возвращать ссылку

// на локальную переменную.

int &f()

{

 int i=10;

 return i;

}

При завершении функции f() локальная переменная i выйдет за пределы области видимости. Следовательно, ссылка на переменную i, возвращаемая функцией f(), будет неопределенной. В действительности некоторые компиляторы не скомпилируют функцию f() в таком виде, и именно по этой причине. Однако проблема такого рода может быть создана опосредованно, поэтому нужно внимательно отнестись к тому, на какой объект будет возвращать ссылку ваша функция.

Создание ограниченного массива

Ссылочный тип в качестве типа значения, возвращаемого функцией, можно с успехом применить для создания ограниченного массива. Как вы знаете, при выполнении С++-кода проверка нарушения границ при индексировании массивов не предусмотрена. Это означает, что может произойти выход за границы области памяти, выделенной для массива. Другими словами, может быть задан индекс, превышающий размер массива. Однако путем создания ограниченного, или безопасного, массива выход за его границы можно предотвратить. При работе с таким массивом любой выходящий за установленные границы индекс не допускается для индексирования массива.

Один из способов создания ограниченного массива иллюстрируется в следующей программе.

// Простой способ организации безопасного массива.

#include <iostream>

using namespace std;

int &put(int i); // Помещаем значение в массив.

Int get(int i); // Считываем значение из массива.

int vals[10];

int error = -1;

Int main()

{

 put(0) = 10; // Помещаем значения в массив.

 put(1) = 20;

 put(9) = 30;

 cout << get(0) << ' ';

 cout << get(1) << ' ';

 cout << get(9) << ' ';

 // А теперь специально генерируем ошибку.

 put(12) =1; // Индекс за пределами границ массива.

return 0;

}

// Функция занесения значения в массив.

int &put(int i)

{

 if(i>=0 && i<10)

   return vals[i]; // Возвращаем ссылку на i-й элемент.

  else {

   cout << "Ошибка нарушения границ!";

   return error; // Возвращаем ссылку на error.

  }

}

// Функция считывания значения из массива.

Int get(int i)

{

 if(i>=0 && i<10)

   return vals[i]; // Возвращаем значение i-го элемента.

  else {

   cout << "Ошибка нарушения границ!";

   return error; // Возвращаем значение переменной error.

  }

}

Результат, полученный при выполнении этой программы, выглядит так.

10 20 30 Ошибка нарушения границ!

В этой программе создается безопасный массив, предназначенный для хранения десяти целочисленных значений. Чтобы поместить в него значение, используйте функцию put(), а чтобы прочитать нужный элемент массива, вызовите функцию get(). При использовании обеих функций индекс интересующего вас элемента задается в виде аргумента. Как видно из текста программы, функции get() и put() не допускают выход за границы области памяти, выделенной для массива. Обратите внимание на то, что функция put() возвращает ссылку на заданный элемент и поэтому законно используется в левой части инструкции присваивания.

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

Независимые ссылки

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

Независимая ссылка — это просто еще одно название для переменных некоторого иного типа.

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

#include <iostream>

using namespace std;

Int main()

{

 int j, k;

 int &i = j; // независимая ссылка

 j = 10;

 cout << j << " " << i; // Выводится: 10 10

 k = 121;

 i = k; // Копирует в переменную j значение переменной k, а не адрес переменной k.

 cout << "" << j; // Выводится: 121

 return 0;

}

При выполнении эта программа выводит следующие результаты.

10 10

Адрес, который содержит ссылочная переменная, фиксирован и его нельзя изменить. Следовательно, при выполнении инструкции i = k в переменную j (адресуемую ссылкой i) копируется значение переменной k, а не ее адрес. В качестве еще одного примера отметим, что после выполнения инструкции i++ ссылочная переменная i не станет содержать новый адрес, как можно было бы предположить. В данном случае на 1 увеличится содержимое переменной j.

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

Ограничения при использовании ссылок









Читайте также:

Последнее изменение этой страницы: 2016-03-17; Просмотров: 98;


lektsia.info 2017 год. Все права принадлежат их авторам! Главная