|
Программирование >> Поддержка объектно-ориентированного программирования
Бьерн Страуструп. стандартное значение параметра ($$4.6.7). Рассмотрим функцию: void f(int val, int& ref) val++; ref++; При вызове f() в выражении val++ увеличивается локальная копия первого фактического параметра, тогда как в ref++ - сам второй фактический параметр увеличивается сам. Поэтому в функции void g() int i = 1; int j = f(i,j); увеличится значение j, но не i. Первый параметр i передается по значению, а второй параметр j передается по ссылке. В $$2.3.10 мы говорили, что функции, которые изменяют свой передаваемый по ссылке параметр, труднее понять, и что поэтому лучше их избегать (см. также $$1 0.2.2). Но большие объекты, очевидно, гораздо эффективнее передавать по ссылке, чем по значению. Правда можно описать параметр со спецификацией const, чтобы гарантировать, что передача по ссылке используется только для эффективности, и вызываемая функция не может изменить значение объекта: void f(const large& arg) значение arg нельзя изменить без явных операций преобразования типа Если в описании параметра ссылки const не указано, то это рассматривается как намерение изменять передаваемый объект: void g(large& arg); считается, что в g() arg будет меняться том, Отсюда мораль: используйте const всюду, где возможно. Точно так же, описание параметра, являющегося указателем, со спецификацией const говорит о что указуемый объект не будет изменяться в вызываемой функции. Например: extern int strlen(const char*); из <string.h> extern char* strcpy(char* to, const char* from); extern int strcmp(const char*, const char*); Значение такого приема растет вместе с ростом программы. Отметим, что семантика передачи параметров отличается от семантики присваивания. Это различие существенно для параметров, являющихся const или ссылкой, а также для параметров с типом, определенным пользователем ($1 .4.2). Литерал, константу и параметр, требующий преобразования, можно передавать как параметр типа const&, но без спецификации const передавать нельзя. Допуская преобразования для параметра типа const T&, мы гарантируем, что он может принимать значения из того же множества, что и параметр типа T, значение которого передается при необходимости с помощью временной переменной. float fsqrt(const float&); void g(double d) float r; r = fsqrt(2.0f); r = fsqrt(r); r = fsqrt(d); функция sqrt в стиле Фортрана передача ссылки на временную переменную, содержащую 2.0f передача ссылки на r передача ссылки на временную переменную, содержащую float(d) Запрет на преобразования типа для параметров-ссылок без спецификации const введен для того, чтобы избежать нелепых ошибок, связанных с использованием при передаче параметров временных переменных: void update(float& i); void g(double d) float r; update(2.0f); ошибка: параметр-константа update(r); нормально: передается ссылка на r update(d); ошибка: здесь нужно преобразовывать тип 4.6.4 Возвращаемое значение Если функция не описана как void, она должна возвращать значение. Например: int f() { } ошибка void g() { } нормально Возвращаемое значение указывается в операторе return в теле функции. Например: int fac(int n) { return (n>1) ? n*fac(n-1) : 1; } В теле функции может быть несколько операторов return: int fac(int n) if (n > 1) return n*fac(n-1); else return 1; Подобно передаче параметров, операция возвращения значения функции эквивалентна инициализации. Считается, что оператор return инициализирует переменную, имеющую тип возвращаемого значения. Тип выражения в операторе return сверяется с типом функции, и производятся все стандартные и пользовательские преобразования типа. Например: double f() ... return 1 ; неявно преобразуется в double( 1 ) При каждом вызове функции создается новая копия ее формальных параметров и автоматических переменных. Занятая ими память после выхода из функции будет снова использоваться, поэтому неразумно возвращать указатель на локальную переменную. Содержимое памяти, на которую настроен такой указатель, может измениться непредсказуемым образом: int* f() int local = 1; ... return &local; ошибка Эта ошибка не столь типична, как сходная ошибка, когда тип функции - ссылка: int& f() int local = 1; ... return local; ошибка К счастью, транслятор предупреждает о том, что возвращается ссылка на локальную переменную. Вот другой пример: int& f() { return 1; } ошибка 4.6.5 Параметр-массив Если в качестве параметра функции указан массив, то передается указатель на его первый элемент. Например: int strlen(const char*); void f() char v[] = массив ; strlen(v); strlen( Николай ); Это означает, что фактический параметр типа T[] преобразуется к типу T*, и затем передается. Поэтому присваивание элементу формального параметра-массива изменяет этот элемент. Иными словами, массивы отличаются от других типов тем, что они не передаются и не могут передаваться по значению. В вызываемой функции размер передаваемого массива неизвестен. Это неприятно, но есть несколько способов обойти данную трудность. Прежде всего, все строки оканчиваются нулевым символом, и значит их размер легко вычислить. Можно передавать еще один параметр, задающий размер массива. Другой способ: определить структуру, содержащую указатель на массив и размер массива, и передавать ее как параметр (см. также $$1.2.5). Например: void compute1(int* vec ptr, int vec size); 1-ый способ struct vec { 2- ой способ int* ptr; int size; void compute2(vec v); Сложнее с многомерными массивами, но часто вместо них можно использовать массив указателей, сведя эти случаи к одномерным массивам. Например: char* day[] = { mon , tue , wed , thu , fri , sat , sun Теперь рассмотрим функцию, работающую с двумерным массивом - матрицей. Если размеры обоих индексов известны на этапе трансляции, то проблем нет: void print m34(int m[3][4]) for (int i = 0; i<3; { for (int j = 0; j<4; J++) cout << << m[i][j]; cout << \n; Конечно, матрица по-прежнему передается как указатель, а размерностиприведены просто для полноты описания. Первая размерность для вычисления адреса элемента неважна($$Р.8.2.4), поэтому ее можно передавать как параметр: void print mi4(int m[][4], int dim1)
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |