|
Программирование >> Структурное программирование
3.17. Ссылки и ссылочные параметры Во многих языках программирования имеются два способа обращения к функциям - вызов по значению и вызов по ссылке. Когда аргумент передается вызовом по значению, создается копия аргумента и она передается вызываемой функции. Изменения копии не влияют на значение оригинала в операторе вызова. Это предотвращает случайный побочный эффект, который так сильно мешает развитию корректного и надежного программного обеспечения. Все аргументы, которые передавались в функции в программах этой главы, передавались вызовом по значению. Один из недостатков вызова по значению состоит в том, что если передается большой элемент данных, создание копии этих данных может привести к значительным потерям времени выполнения. В этом разделе мы познакомимся со ссылочными параметрами - первым из двух средств, которыми снабжен С+-Ь для вызова по ссылке. В случае вызова по ссылке оператор вызова дает вызываемой функции возможность прямого доступа к передаваемым данным, а также возможность изменения этих данных. Вызов по ссылке хорош в смысле производительности, потому что он исключает накладные расходы на копирование больших объемов данных, но вызов по ссылке может ослабить защищенность, потому что вызываемая функция может испортить передаваемые в нее данные. Ссылочный параметр - это псевдоним соответствующего аргумента. Чтобы показать, что параметр функции передан по ссылке, после типа параметра в прототипе функции ставится символ амперсанда (&); такое же обозначение используется в списке типов параметров в заголовке функции. Например, объявление int SCQUnt в заголовке функции может читаться как count является ссылкой на int*. В вызове функции достаточно указать имя переменной и она будет передана по ссылке. Тогда упоминание в теле вызываемой функции переменной по имени ее параметра в действительности является обращением к исходной переменной в вызывающей функции и эта исходная переменная может быть изменена непосредственно вызываемой функцией. Программа на рис. 3.20 сравнивает вызовы по значению и по ссылке с использованием ссылочных параметров. Стили аргументов в обращениях к squareByValue и squareByReference идентичны, т.е. обе переменных просто упоминаются по имени. Без проверки прототипов или описаний функций невозможно выяснить, вызовы какой из этих двух функций могут изменять ее аргументы. Типичная ошибка программирования 3.22 Поскольку ссылочные параметры упоминаются в теле вызываемой функции только по имени, программист может нечаянно принять ссылочные параметры за параметры, передаваемые по значению. Это может привести к неожиданным эффектам, если исходные копии переменных изменяются вызывающей функцией. В главе 5 мы будем рассматривать указатели; мы увидим, что указатели можно использовать как альтернативную форму вызова по ссылке, в которой способ вызова ясно указывает на передачу по ссылке (и на возможное изменение аргументов в операторе вызова). Сравнение вызовов по значению и по ссылке #include <iostream.h> int squareByValue(int); void squareByReference(int &) ; main ( ) { int X = 2, z = 4; cout << x = << X << перед squareByValue << endl Значение, возвращенное squareByValue: << squareByValue(x) << endl << x = << X << после squareByValue << endl endl; cout z = z перед squareByReference endl; squareByReference (z); cout << z = << z << после squareByReference endl; return 0; int squareByValue(int a) return a *= a; аргумент оператора вызова не изменяется void squareByReference(int ScRef) cRef *= cRef; аргумент оператора вызова изменяется X = 2 перед squareByValue Значение, возвращенное squareByValue: 4 X = 2 после squareByValue Z = 4 перед squareByReference а. Z = 16 после squareByReference Рис. 3.20. Пример вызова по ссылке Совет по повышению эффективности 3.8 Для передачи больших объектов используйте константный ссылочный параметр, чтобы обеспечить защиту параметров, как при вызове по значению, и в то же время избежать накладных расходов при передаче копии большого объекта. Чтобы определить ссылку как константу, разместите перед описателем типа в объявлении параметра спецификацию const. Обратите внимание на место символа & в списке параметров функции squareByReference. Некоторые программисты на С++ предпочитают записывать int& cRef вместо int &cRef. main() ( int X = 3, &у; Ошибка: у должна получить начальное значение cout х = X endl у = у endl; у = 7; cout х = << X endl у = у << endl; return 0; I } Compiling FIG3 21.CPP: Error FIG3 21.CPP 6: Reference variable y must be initialized Рис. 3.21. Попытка использовать ссылку без заданного начального значения Типичная ошибка программирования 3.23 При объявлении множества ссылок в одном операторе делается неверное предположение, что действие символа амперсанд & распространяется на весь записанный через запятую список имен переменных. Чтобы объявить переменные х, у и z как ссылки на целое число, используйте запись int &х, &у, &г; вместо неправильной записи int& X, у, z; или другой распространенной неправильной записи int 8ix, у. z; Замечание по технике программирования 3.16 Чтобы обеспечить одновременно ясность программы и ее производительность, многие программисты на С++ предпочитают, чтобы аргументы, которые могут изменяться, передавались бы функциям с помощью указателей, аргументы, не предназначенные для изменения, передавались бы вызовом по значению, а большие неизменяемые аргументы передавались бы функциям путем использования константных ссылок. Ссылки можно также использовать как псевдонимы для других переменных внутри функций (хотя для этого и мало оснований). Например, фрагмент int. count =1; объявление целой переменной count int ScRef = count; создание cRef как псевдонима для count +4-cRef; приращение count (используется псевдоним) дает приращение переменной count, используя ее псевдоним cRef. Ссылочные переменные должны получать начальные условия в их объявлениях (смотри рис. 3.21 и рис. 3.22) и не могут переприсваиваться как псевдонимы другим переменным. Как только ссылка объявляется как псевдоним другой переменной, все операции, выполняемые с псевдонимом (т.е. ссылкой), на самом деле будут выполняться с самой истинной переменной. Псевдоним - лишь другое имя для истинной переменной, для него не резервируется никакого места в памяти. Определение адреса ссылки и сравнение ссылок не вызывают синтаксических ошибок; на самом деле каждая операция выполняется над переменной, для которой ссылка является псевдонимом. Аргумент-ссылка должен быть L-величиной, не константой и не выражением, которое возвращает К-величину. Ссьшка должна получить начальное значение ttinclude <iostream.h>
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |