Литмир - Электронная Библиотека
A
A

4.5.1. Зачем нужны функции

 

Программирование. Принципы и практика использования C++ Исправленное издание - _001.png
 Функции нужны в ситуациях, когда требуется выделить некие вычисления и присвоить им конкретное имя, руководствуясь следующими соображениями.

• Эти вычисления логически отделены от других.

• Отделение вычислений делает программу яснее (с помощью присваивания имен функциям).

• Функцию можно использовать в разных местах программы.

• Использование функций упрощает отладку программы.

В дальнейшем мы увидим много примеров, в которых следует руководствоваться этими соображениями. Обратите внимание на то, что в реальных программах используются тысячи функций и даже несколько сотен тысяч функций. Очевидно, что мы никогда не сможем понять такие программы, если их части (т.е. фрагменты вычислений) не будут отделены друг от друга и не получат имен. Кроме того, как мы вскоре убедимся, многие функции часто оказываются полезными в разных ситуациях, и повторять один и тот же код каждый раз довольно утомительно. Например, вы, конечно, можете писать выражения вида

x*x
, или
7*7
, или
(x+7)*(x+7)
, а не
square(x)
,
square(7)
или
square(x+7)
. Однако функция square сильно упрощает такие вычисления. Рассмотрим теперь извлечение квадратного корня (в языке С++ эта функция называется
sqrt
): можете написать выражение
sqrt(x)
, или
sqrt(7)
, или
sqrt(x+7)
, а не повторять код, вычисляющий квадратный корень, запутывая программу. И еще один аргумент: можете даже не интересоваться, как именно вычисляется квадратный корень числа в функции
sqrt(x)
, — достаточно просто передать функции аргумент
x
.

В разделе 8.5 мы рассмотрим множество технических деталей, связанных с функциями, а пока рассмотрим еще один пример. Если мы хотим действительно упростить цикл в функции

main()
, то можно было бы написать такой код:

void print_square(int v)

{

  cout << v << '\t' << v*v << '\n';

}

int main()

{

  for (int i = 0; i<100; ++i) print_square(i);

}

Почему же мы не использовали версию программы на основе функции

print_square()
? Дело в том, что эта программа ненамного проще, чем версия, основанная на функции
square()
, и, кроме того,

• функция

print_square()
является слишком специализированной и вряд ли будет использована в другой программе, в то время как функция
square()
, скорее всего, будет полезной для других пользователей;

• функция

square()
не требует подробной документации, а функция
print_square()
очевидно требует пояснений.

Функция

print_square()
выполняет два логически отдельных действия:

• печатает числа;

• вычисляет квадраты.

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

square()
является более предпочтительной.

В заключение попробуем ответить, почему мы использовали функцию

square(i)
, а не выражение
i*i
, использованное в первой версии программы? Одной из целей функций является упрощение кода путем распределения сложных вычислений по именованным функциям, а для программы 1949 года еще не было аппаратного обеспечения, которое могло бы непосредственно выполнить операцию “умножить”. По этой причине в первоначальной версии этой программы выражение
i*i
представляло собой действительно сложное вычисление, как если бы вы выполняли его на бумаге. Кроме того, автор исходной версии, Дэвид Уилер, ввел понятие функций (впоследствии названных процедурами) в современном программировании, поэтому было вполне естественно, что он использовал их в своей программе.

ПОПРОБУЙТЕ

Реализуйте функцию

square()
не используя оператор умножения; иначе говоря, выполните умножение
x*x
с помощью повторного сложения (начиная с переменной, равной нулю, и
х
раз добавляя к ней число
x
). Затем выполните версию первой программы, используя функцию
square()
.

4.5.2. Объявления функций

Вы заметили, что вся информация, необходимая для вызова функции, содержится в первой строке ее объявления? Рассмотрим пример.

int square(int x)

Этой строки уже достаточно, чтобы написать инструкцию

int x = square(44);

На самом деле нам не обязательно заглядывать в тело функции. В реальных программах мы часто не хотим углубляться в детали реализации тела функции. Зачем нам знать, что написано в теле стандартной функции

sqrt()
? Мы знаем, что она извлекает квадратный корень из своего аргумента. А зачем нам знать, как устроено тело функции
square()
? Разумеется, в нас может разжечься любопытство. Но в подавляющем большинстве ситуаций достаточно знать, как вызвать функцию, взглянув на ее определение. К счастью, в языке С++ существует способ, позволяющий получить эту информацию, не заглядывая в тело функции. Эта конструкция называется объявлением функции.

int square(int);      // объявление функции square

double sqrt(double);  // объявление функции sqrt

Обратите внимание на завершающие точку с запятой. Они используются в объявлении функции вместо ее тела, заданного в определении.

int square(int x) // определение функции square

{

  return x*x;

}

Итак, если мы хотим просто использовать функцию, то достаточно написать ее объявление, а чаще — выполнить директиву

#include
. Определение функции может быть в любом другом месте. Это “любое другое место” мы укажем в разделах 8.3 и 8.7. В более крупных программах разница между объявлениями и определениями становится существеннее. В этих программах определения позволяют сосредоточиться на локальном фрагменте программы (см. раздел 4.2), не обращая внимания на остальную часть кода.

53
{"b":"847443","o":1}