именно этипеременныеучаствуютвпоследующихвычисленияхвнутрифункции.
3.1 Передача параметров по значению
Функции, принимающиепараметрыпо значению, "безопасны" втомсмысле,
что онинемогутслучайноизменитьпеременныевызывающейфункции (т.е. уфунк-
ций нетскрытыхпобочных эффектов). Большинствофункцийпроектируютсяименно
таким образом.
Программа 3.1 поясняет, почемуважногарантировать "сохранность" перемен-
ных вызывающейфункции. Этапрограммадолжнавыводитьнаэкранфакториали
корень изчисла, введенногопользователем:
Введите положительное число:
4
Факториал 4! равен 24, а квадратный корень из 4 равен 2.
Для извлеченияквадратногокорняприменяетсябиблиотечнаяфункция
"sqrt(...)". Библиотечнойфункциидлявычисленияфакториаланет, поэтомупри-
дется написатьсобственнуюфункцию (вычисляющуюдлялюбогоположительного
целого числаn значение n!=(1*2*3*...*n)).
#include<iostream.h>
#include<math.h>
int factorial(int number);
// ГЛАВНАЯ ФУНКЦИЯ:
int main()
{
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 factorial(int number)
{
int product = 1;
for ( ; number > 0 ; number--)
product *= number;
34
return product;
}
// КОНЕЦ ФУНКЦИИ
Программа 3.1.
Если быфункция "factorial(...)" изменялапеременнуювызывающей
функции, топрограмма 3.1 выдавалабыследующийответ (формальноправильный,
но посмыслузадачинекорректный):
Введите положительное число:
4
Факториал 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";
35
}
// КОНЕЦ ФУНКЦИИ
// ФУНКЦИЯ ВЫЧИСЛЕНИЯ ПЛОЩАДИ:
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 )
36
{
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(...)" имногих
других математическихфункций). Поэтомувпрограммах, вызывающих
37
"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;
}
Главный файл программы 6.1.
Обратите внимание, чтоимяфайластандартнойбиблиотеки "iostream.h" вди-
рективе препроцессора "include" заключеновугловыескобки ("<>"). Файлысимена-
ми вугловыхскобкахпрепроцессорищетвбиблиотечныхкаталогах, указанныхвна-
стройках компилятора. Именапользовательскихзаголовочныхфайловобычноза-
ключаются вдвойныекавычки, ипрепроцессорищетихвтекущемкаталогепро-
граммы.
Далее приведеносодержимоефайла "averages.h". Внем естьидентификатор
препроцессора "AVERAGES_H" ислужебныесловапрепроцессора "ifndef" ("еслинеоп-
ределено"), "define" ("определить") и "endif" ("конецдирективыif"). Идентифика-
тор "AVERAGES_H" являетсяглобальным символическимименемзаголовочногофайла.
Первые двестрокифайласлужатзащитойотповторнойобработкитекстазаголовоч-
ного файлапрепроцессором, наслучай, есливисходномтекстепрограммыстрока
"#include "averages.h"" встречаетсянесколькораз.
В заголовочныхфайлах, кромепрототиповфункций, часторазмещаютсяопи-
сания глобальных константипользовательскихтипов. Подробнееобэтомговоритсяв