Программирование >>  Поддержка объектно-ориентированного программирования 

1 ... 30 31 32 [ 33 ] 34 35 36 ... 120


Бьерн Страуструп.

стандартное значение параметра ($$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)



1 ... 30 31 32 [ 33 ] 34 35 36 ... 120

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика