Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Cpp_Страуструп.doc
Скачиваний:
16
Добавлен:
03.05.2015
Размер:
3.2 Mб
Скачать

4.6.3 Передача параметров

При вызове функции выделяется память для ее формальных параметров,

и каждый формальный параметр инициализируется значением

соответствующего фактического параметра. Семантика передачи

параметров тождественна семантике инициализации. В частности, сверяются

типы формального и соответствующего ему фактического параметра, и

выполняются все стандартные и пользовательские преобразования типа.

Существуют специальные правила передачи массивов ($$4.6.5).

Есть возможность передать параметр, минуя контроль типа ($$4.6.8),

и возможность задать стандартное значение параметра ($$4.6.7).

Рассмотрим функцию:

void f(int val, int& ref)

{

val++;

ref++;

}

При вызове f() в выражении val++ увеличивается локальная копия

первого фактического параметра, тогда как в ref++ - сам второй

фактический параметр увеличивается сам. Поэтому в функции

void g()

{

int i = 1;

int j = 1;

f(i,j);

}

увеличится значение j, но не i. Первый параметр i передается по

значению, а второй параметр j передается по ссылке. В $$2.3.10

мы говорили, что функции, которые изменяют свой передаваемый

по ссылке параметр, труднее понять, и что поэтому лучше их избегать

(см. также $$10.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&); // функция sqrt в стиле Фортрана

void g(double d)

{

float r;

r = fsqrt(2.0f); // передача ссылки на временную

// переменную, содержащую 2.0f

r = fsqrt(r); // передача ссылки на r

r = fsqrt(d); // передача ссылки на временную

// переменную, содержащую float(d)

}

Запрет на преобразования типа для параметров-ссылок без спецификации

const введен для того, чтобы избежать нелепых ошибок, связанных

с использованием при передаче параметров временных переменных:

void update(float& i);

void g(double d)

{

float r;

update(2.0f); // ошибка: параметр-константа

update(r); // нормально: передается ссылка на r

update(d); // ошибка: здесь нужно преобразовывать тип

}