Чтение онлайн

на главную

Жанры

Программирование. Принципы и практика использования C++ Исправленное издание
Шрифт:

// считываем vx и vy из входного потока

larger(vx,vy);

// ...

}

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

larger
.

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

пятидесяти лет, — все аргументы передаются по ссылке. Многие программисты-вычислители копируют проекты, разработанные на языке Fortran, и вызывают функции, написанные на нем.

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

8.5.7. Проверка аргументов и преобразование типов

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

void f(T x);

f(y);

T x=y; // инициализация переменной x значением переменной y

// (см раздел 8.2.2)

Вызов

f(y)
является корректным, если инициализация
T x=y;
произошла и если обе переменные с именем
x
могут принимать одно и то же значение. Рассмотрим пример.

void f(double);

void g(int y)

{

f(y);

double x(y); // инициализируем переменную x значением

// переменной y (см. раздел 8.2.2)

}

Обратите внимание на то, что для инициализации переменной

x
значением переменной
y
необходимо преобразовать переменную типа
int
в переменную типа
double
. То же самое происходит при вызове функции
f
. Значение типа
double
, полученное функцией
f
, совпадает со значением, хранящимся в переменной
x
.

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

void ff(int);

void gg(double x)

{

ff(x); // как понять, имеет ли это смысл?

}

Если вы действительно хотите усечь значение типа

double
до значения типа
int
, то сделайте это явно.

void ggg(double x)

{

int x1 = x; // усечение x

int x2 = int(x);

ff(x1);

ff(x2);

ff(x); //
усечение x

ff(int(x));

}

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

8.5.8. Реализация вызова функции

Как же на самом деле компилятор выполняет вызов функции? Функции

expression
,
term
и
primary
, описанные в главах 6 и 7, прекрасно подходят для иллюстрации этой концепции за исключением одной детали: они не принимают никаких аргументов, поэтому на их примере невозможно объяснить механизм передачи параметров. Однако погодите! Они должны принимать некую входную информацию; если бы это было не так, то они не смогли бы делать ничего полезного. Они принимают неявный аргумент, используя объект
ts
класса
Token_stream
для получения входной информации; объект
ts
является глобальной переменной. Это несколько снижает прозрачность работы программы. Мы можем улучшить эти функции, позволив им принять аргумент типа
Token_stream&
. Благодаря этому нам не придется переделывать ни один вызов функции.

Во-первых, функция expression совершенно очевидна; она имеет один аргумент (

ts
) и две локальные переменные (
left
и
t
).

double expression(Token_stream& ts)

{

double left = term(ts);

Token t = ts.get;

// ...

}

Во-вторых, функция

term
очень похожа на функцию
expression
, за исключением того, что имеет дополнительную локальную переменную (
d
), которая используется для хранения результата деления (раздел
case '/'
).

double term(Token_stream& ts)

{

double left = primary(ts);

Token t = ts.get;

// ...

case '/':

{

double d = primary(ts);

// ...

}

// ...

}

В-третьих, функция

primary
очень похожа на функцию
term
, за исключением того, что у нее нет локальной переменной
left
.

double primary(Token_stream& ts)

{

Token t = ts.get;

switch (t.kind) {

case '(':

{ double d = expression(ts);

// ...

}

// ...

}

}

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

Поделиться:
Популярные книги

Идеальный мир для Лекаря 15

Сапфир Олег
15. Лекарь
Фантастика:
боевая фантастика
юмористическая фантастика
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 15

Младший сын князя

Ткачев Андрей Сергеевич
1. Аналитик
Фантастика:
фэнтези
городское фэнтези
аниме
5.00
рейтинг книги
Младший сын князя

Попала, или Кто кого

Юнина Наталья
Любовные романы:
современные любовные романы
5.88
рейтинг книги
Попала, или Кто кого

Имперец. Том 4

Романов Михаил Яковлевич
3. Имперец
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Имперец. Том 4

Проданная Истинная. Месть по-драконьи

Белова Екатерина
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Проданная Истинная. Месть по-драконьи

Газлайтер. Том 5

Володин Григорий
5. История Телепата
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Газлайтер. Том 5

Приручитель женщин-монстров. Том 2

Дорничев Дмитрий
2. Покемоны? Какие покемоны?
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Приручитель женщин-монстров. Том 2

Путь Шедара

Кораблев Родион
4. Другая сторона
Фантастика:
боевая фантастика
6.83
рейтинг книги
Путь Шедара

Последний Паладин. Том 4

Саваровский Роман
4. Путь Паладина
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Последний Паладин. Том 4

Возрождение Феникса. Том 1

Володин Григорий Григорьевич
1. Возрождение Феникса
Фантастика:
фэнтези
попаданцы
альтернативная история
6.79
рейтинг книги
Возрождение Феникса. Том 1

Я все еще не князь. Книга XV

Дрейк Сириус
15. Дорогой барон!
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Я все еще не князь. Книга XV

Чужая дочь

Зика Натаэль
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Чужая дочь

Черный Маг Императора 6

Герда Александр
6. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
7.00
рейтинг книги
Черный Маг Императора 6

В теле пацана

Павлов Игорь Васильевич
1. Великое плато Вита
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
В теле пацана