Способы передачи параметров внутрь функций

Во всех рассмотренных до сих пор примерах параметры функций передавались

по значению. При вызове из функции "main()" вызываемой функции передаются ко-

пии указанных переменных. Например, в программе 2.1 функции "area(...)" переда-

ются текущие значения переменных "this_length" и "this_width". Затем функция

"area(...)" сохраняет переданные значения в собственных локальных переменных, и

именно эти переменные участвуют в последующих вычислениях внутри функции.

3.1 Передача параметров по значению

Функции, принимающие параметры по значению, "безопасны" в том смысле,

что они не могут случайно изменить переменные вызывающей функции (т.е. у функ-

ций нет скрытых побочных эффектов). Большинство функций проектируются именно

таким образом.

Программа 3.1 поясняет, почему важно гарантировать "сохранность" перемен-

ных вызывающей функции. Эта программа должна выводить на экран факториал и

корень из числа, введенного пользователем:

Введите положительное число:

Факториал 4! равен 24, а квадратный корень из 4 равен 2.

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

"sqrt(...)". Библиотечной функции для вычисления факториала нет, поэтому при-

дется написать собственную функцию (вычисляющую для любого положительного

целого числа n значение n!=(1*2*3*...*n)).

ГЛАВНАЯ ФУНКЦИЯ:

int whole_number;

cout << "Введите положительное число:\n";

cin >> whole_number;

cout << "Факториал " << whole_number << "! равен ";

cout << factorial(whole_number);

cout << ", а квадратный корень из " << whole_number;

cout << " равен " << sqrt(whole_number) << ".\n";

return 0;

// КОНЕЦ ГЛАВНОЙ ФУНКЦИИ

ФУНКЦИЯ ДЛЯ ВЫЧИСЛЕНИЯ ФАКТОРИАЛА:

int product = 1;

for (; number > 0; number--)

product *= number;


return product;

}

// КОНЕЦ ФУНКЦИИ


Программа 3.1.


Если бы функция "factorial(...)" изменяла переменную вызывающей

функции, то программа 3.1 выдавала бы следующий ответ (формально правильный,

но по смыслу задачи некорректный):

Введите положительное число:

Факториал 4! равен 24, а квадратный корень из 0 равен 0.

3.2 Передача параметров по ссылке

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

данного ей параметра. Рассмотрим программу 2.1. С 10-й по 14-ю строку в ней вы-

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

При структурном программировании независимые по смыслу части программы

принято оформлять в виде отдельных функций. Для получения данных от пользова-

теля создадим функцию "get_dimensions". В данном случае необходимо, чтобы эта

функция изменяла значения переменных "this_length" и "this_width" (переданных ей

в качестве параметров) – помещала в них значения, введенные пользователем с кла-

виатуры. Изменение параметров функции возможно при передаче параметров по

ссылке. У таких параметров в заголовке функции после имени типа указывается сим-

вол "&".

#include<iostream.h>

int area(int length, int width);

void get_dimensions(int& length, int& width);

// ГЛАВНАЯ ФУНКЦИЯ:

int main()

{

int this_length, this_width;

get_dimensions(this_length, this_width);

cout << "Площадь прямоугольника с размерами ";

cout << this_length << "x" << this_width;

cout << " равна " << area(this_length, this_width) << "\n";

return 0;

}

// КОНЕЦ ГЛАВНОЙ ФУНКЦИИ

// ФУНКЦИЯ ВВОДА РАЗМЕРОВ ПРЯМОУГОЛЬНИКА:

void get_dimensions(int& length, int& width)

{

cout << "Введите длину: ";

cin >> length;

cout << "Введите ширину: ";

cin >> width;

cout << "\n";



}

// КОНЕЦ ФУНКЦИИ

// ФУНКЦИЯ ВЫЧИСЛЕНИЯ ПЛОЩАДИ:

int area(int length, int width)

{

return length*width;

}

// КОНЕЦ ФУНКЦИИ

Программа 3.2.

Функция "get_dimensions" изменяет значения параметров "this_length" и

"this_width", но не возвращает никакого значения (т.е. не является "функцией" в ма-

тематическом смысле). Этот факт отражается и в прототипе, и в определении функ-

ции – в качестве возвращаемого значения указан тип "void" ("пустой" тип).

4. Полиморфизм и перегрузка функций

Одним из характерных свойств объектно-ориентированного языка, в том числе

и Си++, является полиморфизм – использование одного имени для выполнения раз-

личных действий над различными объектами. Применительно к функциям это назы-

вается перегрузкой. Для основных операций Си++ перегрузка уже встроена в язык:

например, у сложения существует только одно имя, "+", но его можно применять для

сложения как целых, так и вещественных значений. Эта идея расширяется на обра-

ботку операций, определенных пользователем, т.е., функций.

Перегруженные функции имеют одинаковые имена, но разные списки парамет-

ров и возвращаемые значения (см. программу 4.1).

#include<iostream.h>

int average(int first_number, int second_number,

int third_number);

int average(int first_number, int second_number);

// ГЛАВНАЯ ФУНКЦИЯ:

int main()

{

int number_A = 5, number_B = 3, number_C = 10;

cout << "Целочисленное среднее чисел " << number_A << " и ";

cout << number_B << " равно ";

cout << average(number_A, number_B) << ".\n\n";

cout << "Целочисленное среднее чисел " << number_A << ", ";

cout << number_B << " и " << number_C << " равно ";

cout << average(number_A, number_B, number_C) << ".\n";

return 0;

}

// КОНЕЦ ГЛАВНОЙ ФУНКЦИИ

// ФУНКЦИЯ ДЛЯ ВЫЧИСЛЕНИЯ ЦЕЛОЧИСЛЕННОГО СРЕДНЕГО

// ЗНАЧЕНИЯ 3-Х ЦЕЛЫХ ЧИСЕЛ:

int average(int first_number, int second_number,

int third_number)


{

return ((first_number + second_number + third_number)/3);

}

// КОНЕЦ ФУНКЦИИ

// ФУНКЦИЯ ДЛЯ ВЫЧИСЛЕНИЯ ЦЕЛОЧИСЛЕННОГО СРЕДНЕГО

// ЗНАЧЕНИЯ 2-Х ЦЕЛЫХ ЧИСЕЛ:

int average(int first_number, int second_number)

{

return ((first_number + second_number)/2);

}

// КОНЕЦ ФУНКЦИИ

Программа 4.1.

Программа 4.1. выводит на экран сообщения:

Целочисленное среднее чисел 5 и 3 равно 4.

Целочисленное среднее чисел 5, 3 и 10 равно 6.

5. Процедурная абстракция и "хороший" стиль программирования

Функции помогают применять для разработки программ структурный метод

проектирования " сверху вниз ". При этом решаемая задача делится на подзадачи (и за-

тем на под-подзадачи и т.д.). Для решения каждой подзадачи программист реализует

отдельную функцию, при этом ему не нужно знать детали реализации остальных

функций.

Чтобы функцией мог воспользоваться другой программист, она должна иметь

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

возможных возвращаемых значений.

Опытные программисты на начальных этапах разработки часто применяют

пустые функции (заглушки), которые содержат только оператор возврата значения со-

ответствующего типа. Эти функций облегчают отладку главной функции или просто

функции более высокого уровня.

Выделение в решаемой задаче функций методом "сверху вниз" часто называет-

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

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

кальные переменные внутри функций. После реализации программист может рас-

сматривать подобные функции как "черные ящики". Для их использования знать де-

тали реализации не обязательно.

6. Модульное программирование

Помимо метода "сверху вниз", вторым важным методом структурного проек-

тирования является метод модульного программирования. Он предполагает разделе-

ние текста программы на несколько файлов, в каждом из которых сосредоточены не-

зависимые части программы (сгруппированные по смыслу функции).

В программах на Си++ часто применяются библиотечные функции (например,

"sqrt(...)"). Для использования большинства функций, в том числе и библиотечных,

необходимы два файла (в скобках примеры даны для "sqrt(...)"):

Заголовочный файл ("math.h") с прототипом функции ("sqrt(...)" и многих

других математических функций). Поэтому в программах, вызывающих


"sqrt(...)", есть строка "#include <math.h>", а не явное объявление этой

функции.

Файл реализации (для пользовательских функций это файлы с исходным

текстом на Си++, а библиотечные функции обычно хранятся в скомпилиро-

ванном виде в специальных библиотечных файлах, например,

"libcmtd.lib"). Файлы реализации пользовательских функций (обычно с

расширением ".cpp") содержат определения этих функций.

Разделение исходного текста на заголовочные файлы и файлы реализации по-

казано в программе 6.1, которая выполняет те же действия, что и программа 4.1. Те-

перь программа состоит из трех файлов: главного файла, заголовочного файла с опи-

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

зации.

В главном файле содержится следующий текст:

#include <iostream.h>

#include "averages.h"

int main()

{

int number_A = 5, number_B = 3, number_C = 10;

cout << "Целочисленное среднее чисел " << number_A << " и ";

cout << number_B << " равно ";

cout << average(number_A, number_B) << ".\n\n";

cout << "Целочисленное среднее чисел " << number_A << ", ";

cout << number_B << " и " << number_C << " равно ";

cout << average(number_A, number_B, number_C) << ".\n";

return 0;

}


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: